R Notebook covering data generated from healthy samples for Figure 1, Supplementary figure 1 and 2.

LOAD ALL PACKAGES

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
Registered S3 method overwritten by 'cli':
  method     from         
  print.boxx spatstat.geom
── Attaching packages ─────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.6     ✓ dplyr   1.0.7
✓ tidyr   1.1.4     ✓ stringr 1.4.0
✓ readr   2.1.0     ✓ forcats 0.5.1
── Conflicts ────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(Seurat)
Attaching SeuratObject
library(cowplot)
library(RColorBrewer)
library(pheatmap)
library(scales)

Attaching package: ‘scales’

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor

Import functions from the custom R script

source("SPATIAL_FUNCTIONS.R")
package ‘clusterProfiler’ was built under R version 4.1.1
clusterProfiler v4.0.5  For help: https://yulab-smu.top/biomedical-knowledge-mining-book/

If you use clusterProfiler in published research, please cite:
T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou, W Tang, L Zhan, X Fu, S Liu, X Bo, and G Yu. clusterProfiler 4.0: A universal enrichment tool for interpreting omics data. The Innovation. 2021, 2(3):100141. doi: 10.1016/j.xinn.2021.100141

Attaching package: ‘clusterProfiler’

The following object is masked from ‘package:purrr’:

    simplify

The following object is masked from ‘package:stats’:

    filter

Loading required package: AnnotationDbi
Loading required package: stats4
Loading required package: BiocGenerics
Loading required package: parallel

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:parallel’:

    clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport, clusterMap, parApply,
    parCapply, parLapply, parLapplyLB, parRapply, parSapply, parSapplyLB

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval,
    evalq, Filter, Find, get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, order,
    paste, pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
    table, tapply, union, unique, unsplit, which.max, which.min

Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, see
    'citation("Biobase")', and for packages 'citation("pkgname")'.

Loading required package: IRanges
Loading required package: S4Vectors
package ‘S4Vectors’ was built under R version 4.1.1
Attaching package: ‘S4Vectors’

The following object is masked from ‘package:clusterProfiler’:

    rename

The following objects are masked from ‘package:dplyr’:

    first, rename

The following object is masked from ‘package:tidyr’:

    expand

The following objects are masked from ‘package:base’:

    expand.grid, I, unname


Attaching package: ‘IRanges’

The following object is masked from ‘package:clusterProfiler’:

    slice

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

The following object is masked from ‘package:purrr’:

    reduce


Attaching package: ‘AnnotationDbi’

The following object is masked from ‘package:clusterProfiler’:

    select

The following object is masked from ‘package:dplyr’:

    select

IMPORTING THE HEATLTHY SAMPLES

## HEALTHY SAMPLES
## HEALTHY MALE SKIN 1 & 2
HEALTHY.Male.s1 <- Load10X_Spatial(data.dir ="../../FOURTH_RUN/SAMPLE A1/",slice="ST-HM-1-R1")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HM.1.R1; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hm.1.r1_ to sthm1r1_
HEALTHY.Male.s2 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HM-1/",slice="ST-HM-1-R2")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HM.1.R2; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hm.1.r2_ to sthm1r2_
## HEALTHY FEMALE SKIN 1 & 2 (FROM THE SAME DONOR)
HEALTHY.Female1.s1 <- Load10X_Spatial(data.dir ="../../FOURTH_RUN/SAMPLE B1/",slice="ST-HF-1-R1")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HF.1.R1; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hf.1.r1_ to sthf1r1_
HEALTHY.Female1.s2 <- Load10X_Spatial(data.dir ="../../FIFTH_RUN/SAMPLE D1/",slice="ST-HF-1-R2")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HF.1.R2; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hf.1.r2_ to sthf1r2_
HEALTHY.Female1.s3 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HF-1/",slice="ST-HF-1-R3")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HF.1.R3; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hf.1.r3_ to sthf1r3_
## HEALTHY FEMALE
HEALTHY.Female2.s1 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HF-2E/",slice="ST-HF-2-R1")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HF.2.R1; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hf.2.r1_ to sthf2r1_
HEALTHY.Female2.s2 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HF-2F/",slice="ST-HF-2-R2")
'giveCsparse' has been deprecated; setting 'repr = "T"' for youInvalid name supplied, making object name syntactically valid. New object name is ST.HF.2.R2; see ?make.names for more details on syntax validityKeys should be one or more alphanumeric characters followed by an underscore, setting key from st.hf.2.r2_ to sthf2r2_

Import the spots to be removed from loupe browser.

# HEALTHY FEMALE SKIN 2
#REMOVE SPOTS

remove.spots <- read.csv(file="../../CLOUPE_FILES/FIFTH_RUN/D1/OUTLIERS.csv")
subset_spots <- Cells(HEALTHY.Female1.s2)[which((!(rownames(HEALTHY.Female1.s2@meta.data) %in% remove.spots$Barcode)))]
HEALTHY.Female1.s2.clean <- subset(HEALTHY.Female1.s2,cells=subset_spots)

#SAMPLE IDS


HEALTHY.Male.s1$sample.id<- "HV1_S1_R1" 
HEALTHY.Male.s2$sample.id<- "HV1_S1_R2"

HEALTHY.Female1.s1$sample.id <- "HV2_S1_R1"
HEALTHY.Female1.s2.clean$sample.id <- "HV2_S1_R2"
HEALTHY.Female1.s3$sample.id <- "HV2_S2"

HEALTHY.Female2.s1$sample.id <- "HV3_S1"
HEALTHY.Female2.s2$sample.id <- "HV3_S2"

SAMPLE IDS (version 2) - (Full name + Biopsy site)

TRUNK and FA (Forearm)

HEALTHY.Male.s1$orig.ident <- "Healthy Volunteer 1 - TRUNK R1" 
HEALTHY.Male.s2$orig.ident <-"Healthy Volunteer 1 - TRUNK R2"

HEALTHY.Female1.s1$orig.ident <- "Healthy Volunteer 2 - FA R1"
HEALTHY.Female1.s2.clean$orig.ident <- "Healthy Volunteer 2 - FA R2"
HEALTHY.Female1.s3$orig.ident <- "Healthy Volunteer 2 - TRUNK"

HEALTHY.Female2.s1$orig.ident <- "Healthy Volunteer 3 - FA R1"
HEALTHY.Female2.s2$orig.ident <- "Healthy Volunteer 3 - TRUNK"

Compile the samples into one list.

Healthy_Samples <- c(HEALTHY.Male.s1,HEALTHY.Male.s2,HEALTHY.Female1.s1,HEALTHY.Female1.s2.clean,HEALTHY.Female1.s3,HEALTHY.Female2.s1,HEALTHY.Female2.s2)

Generating spatial plots without QC filtering

for (x in Healthy_Samples){
  st_plot(x)
}

QC plots for healthy samples

for (x in Healthy_Samples){
  st_plot_QC(x)
}

QC scatter plots

for (x in Healthy_Samples){
  st_scatter_QC(x)
}

Filtering all samples to remove spots with less than 200 genes expressed

i <- 1
while(i <= length(Healthy_Samples)){
  filtered_data <- st_filter_by_genes(st.data = Healthy_Samples[[i]],x = 200)
  Healthy_Samples[[i]] <- filtered_data
  i <- i+1
}

Batch correction of all samples using Seurat Anchor integeration

new.skin.combined <- st_combine(Healthy_Samples,ndim = 20,res = 0.6)

ADDING ADDITIONAL META-DATA

meta.data_skin <- new.skin.combined@meta.data$orig.ident %>% as.data.frame()
write.csv(meta.data_skin,file="HEALTHY_SAMPLES_ST_META_DATA.csv")

IMPORTING ST META-DATA UPDATED VERSION

meta.data_skin_updated <- read.csv(file="HEALTHY_SAMPLES_ST_META_DATA.csv")

ADDING META-DATA to Seurat object

new.skin.combined@meta.data$orig.ident <- meta.data_skin_updated$orig.ident
new.skin.combined@meta.data$sample.id <- meta.data_skin_updated$sample.id

Determining marker genes for batch corrected healthy samples + heatmap

new.skin.combined.markers <- FindAllMarkers(new.skin.combined, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25,assay = "SCT")
DefaultAssay(new.skin.combined) <- "SCT"
top10 <- new.skin.combined.markers %>%
    group_by(cluster) %>%
    filter(p_val_adj<0.05) %>%
    top_n(n = 10, wt = avg_log2FC) %>%
    filter(gene %in% VariableFeatures(new.skin.combined_V2))
pdf(width = 20,height=15,file = "HEATMAP_HEALTHY_SAMPLES_CLUSTERS_ONLY.pdf")
print(DoHeatmap(new.skin.combined, features = top10$gene,assay = "SCT",group.colors = custom_colors) + NoLegend())
dev.off()

Assign cluster ids

new.cluster.ids <- c("0 Mixed","1 Dermis",
"2 Dermis Adipose","3 Epidermis 1","4 Dermis Connective Tissue","5 Upper follicle (UF) and Perifollicular dermis","6 Epidermis 2","7 Dermis 2","8 Dermis Smooth Muscle","9 Hair follicle","10 Dermis Lymphatics","11 Dermis vasculature")
names(new.cluster.ids) <- levels(new.skin.combined)
new.skin.combined <- RenameIdents(new.skin.combined, new.cluster.ids)
new.skin.combined <- StashIdent(new.skin.combined, save.name = "Spatial.regions")

Defining and viewing color scheme for UMAP and spatial plot

custom_colors <- c("#B4DFFC","#6EAB3D","#FFD700","#A020F0","#FFA500","#AEDD3C","#595959","#D2AF81FF","#3A49FC","#FF0000","#A86F3D","#A18FAA")
show_col(custom_colors)

General UMAP with defined color scheme

UMAP plot split by samples

DimPlot(new.skin.combined,split.by = "sample.id")
## SAVE THE RESULTS
save(new.skin.combined,file = "HEALTHY_SKIN_SAMPLES_ST.RData")

Spatial plot for HV2_S2_R1 /HEALTHY_FEMALE_SAMPLE_1

SAVE OUTPUT TO PDF

pdf(width = 8,height=10,file = "HEALTHY_FEMALE_SAMPLE_1_R2_SPATIAL_PLOT.pdf")
SpatialDimPlot(new.skin.combined,images="HealthyFemale.1.S2",cols = custom_colors,pt.size.factor = 2.4)
dev.off()

VIEW SPATIAL PLOT HERE

SpatialDimPlot(new.skin.combined,images="HealthyFemale.1.S2",cols = custom_colors,pt.size.factor = 2.4)

Generate Spatial plot for all samples

images <- Images(new.skin.combined) %>% as.vector()
for(x in images){
  pdf(width = 8,height=10,file = paste(x,"_SPATIAL_PLOT.pdf"))
  print(SpatialDimPlot(new.skin.combined,images=x,cols = custom_colors,pt.size.factor = 2))
  dev.off()
}

Color scheme for MIA heatmap

col.pal <- RColorBrewer::brewer.pal(9, "OrRd")

MIA - scRNA dataset (Travis et al)

SINGLE CELL DATA FROM TRAVIS PAPER

load("../../TRAVIS_scRNA_DATA/SkinSeuratTotal.Rdata")
# META DATA FROM TRAVIS 
meta.data <- read.csv("../../TRAVIS_scRNA_DATA/Cell_Level_Metadata.csv")
#AddMetaData(SkinSeuratTotal,metadata = meta.data$Specific_CellType,col.name = "Specific_Celltype")
skin.meta.data <- as.data.frame(SkinSeuratTotal@meta.data) %>% rownames_to_column("CellID")
inner_join(x=skin.meta.data,y=meta.data,by="CellID")
SkinSeuratTotal@meta.data <- inner_join(x=skin.meta.data,y=meta.data,by="CellID") %>% column_to_rownames("CellID")
SkinSeuratTotal@meta.data$Celltype <- meta.data$CellType
SkinSeuratTotal@meta.data$Condition <- meta.data$Condition
SkinSeuratTotal@meta.data$Celltype_specific <- meta.data$Specific
SkinSeuratTotal@meta.data$SampleID <- meta.data$SampleCondition
#SUBSET DATA TO ONLY HEALTHY SAMPLES
travis_NM_skin_scRNA<- subset(SkinSeuratTotal,subset = Condition == c("Normal"))
## PROCESS SC RNA DATA
travis_NM_skin_scRNA <- NormalizeData(travis_NM_skin_scRNA)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
travis_NM_skin_scRNA <- FindVariableFeatures(travis_NM_skin_scRNA, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
travis_NM_skin_scRNA <- ScaleData(travis_NM_skin_scRNA)
Centering and scaling data matrix

  |                                                                                                                      
  |                                                                                                                |   0%
  |                                                                                                                      
  |========================================================                                                        |  50%
  |                                                                                                                      
  |================================================================================================================| 100%
travis_NM_skin_scRNA <- RunPCA(travis_NM_skin_scRNA, features = VariableFeatures(object = travis_NM_skin_scRNA))
PC_ 1 
Positive:  SPARC, FTH1, COL6A2, DCN, FSTL1, PPAP2B, C1S, SERPINF1, COL6A1, COL1A2 
       C1R, COL6A3, IGFBP7, CTSK, CCDC80, TIMP2, VCAN, SPARCL1, FBLN1, MFAP4 
       AEBP1, FBLN2, SLIT3, IGFBP4, IGFBP5, ICAM1, MMP2, APOD, FN1, CFH 
Negative:  DMKN, SCEL, SBSN, KRTDAP, DSC1, CALML5, SPINK5, LYPD3, DSG1, TMEM45A 
       CSTA, KRT2, CASP14, TACSTD2, KLK7, IVL, SERPINA12, KRT10, CLDN4, POF1B 
       KRT80, ELOVL4, DHCR24, PERP, LY6G6C, GLTP, PKP1, MAL2, JUP, SLURP1 
PC_ 2 
Positive:  LCP1, LAPTM5, RGS1, SRGN, HLA-DQB1, TYROBP, HLA-DQA1, HLA-DPB1, GPR183, HLA-DRA 
       HLA-DRB1, HLA-DPA1, HLA-DRB5, CD83, FCER1A, CD74, HLA-DQA2, ARL4C, HLA-DQB2, HLA-DMA 
       PTPRC, GNA13, LST1, HLA-DMB, PLEK, CD86, TNFRSF1B, CST7, HLA-DOA, ITGB2 
Negative:  DCN, COL6A2, COL1A2, C1S, C1R, COL6A1, CTSK, CFD, COL6A3, FBLN1 
       FSTL1, MFAP4, TIMP2, CCDC80, VCAN, FBLN2, AEBP1, MMP2, IGFBP5, SLIT3 
       PPAP2B, DPT, SPARC, LUM, OLFML3, FN1, COL3A1, CFH, PCOLCE, APOD 
PC_ 3 
Positive:  CST3, HLA-DQA1, HLA-DPB1, HLA-DRA, HLA-DPA1, HLA-DRB1, HLA-DQB1, HLA-DRB5, C15orf48, CD74 
       HLA-DQA2, HLA-DQB2, LST1, HLA-DMB, HLA-DMA, CPVL, CD83, AIF1, PLEK, CTSS 
       TYROBP, CD86, CTSH, FCER1A, FAM49A, SERPINF1, TSPAN33, HLA-DOA, CSF1R, IFI30 
Negative:  KRT5, KRT14, TNS4, COL17A1, S100A2, KRT15, DSG3, AQP3, IGFBP3, POSTN 
       DSP, ITGA6, SFN, LAMB4, SYT8, BNC1, DST, LAMC2, ITGA2, FGFBP1 
       LAMA3, NRG1, PHLDB2, PERP, MET, EDN1, CDCP1, LAMB3, SERPINB2, IMPA2 
PC_ 4 
Positive:  PLVAP, CD93, ELTD1, DARC, TM4SF1, ECSCR, TSPAN7, AC011526.1, CLDN5, VWF 
       SELE, A2M, EMCN, S1PR1, C2CD4B, CDH5, IFI27, KDR, ERG, ESAM 
       GIMAP5, CSF3, FLT1, GNG11, PTPRB, SOX17, CNKSR3, TACR1, RCAN1, GIMAP6 
Negative:  ARL4C, DCN, PTPRC, KRT5, TNS4, DST, KRT14, LCP1, LAPTM5, CTSK 
       FBLN1, THBS2, CD69, CFD, COL1A2, SAMSN1, AQP3, MXRA5, SERPINF1, RUNX3 
       SYTL3, MFAP4, RGS1, C1S, POSTN, S100A2, DSG3, COL17A1, C1R, CDCP1 
PC_ 5 
Positive:  CPA3, TPSAB1, CTSG, IL1RL1, GATA2, KIT, HDC, GCSAML, HPGD, LAX1 
       SRGN, CPM, TPSD1, PAG1, BATF, SYTL3, CD69, CMA1, TNIK, SAMSN1 
       VWA5A, CALB2, RGS13, SDPR, HEY1, SLC2A3, CHN2, GPR65, HPGDS, TMOD1 
Negative:  KRT5, TNS4, KRT14, IL1R2, AQP3, DSG3, PLEK2, DSP, SFN, COL17A1 
       S100A2, SLC2A1, IGFBP3, HLA-DRA, HLA-DQA1, DST, CDCP1, CLDN1, HLA-DPA1, LAMB3 
       HLA-DPB1, HLA-DRB5, HLA-DQB2, FGFBP1, PERP, POSTN, HLA-DRB1, KRT15, CD74, HLA-DMA 
travis_NM_skin_scRNA <- FindNeighbors(travis_NM_skin_scRNA, dims = 1:40)
Computing nearest neighbor graph
Computing SNN
travis_NM_skin_scRNA <- FindClusters(travis_NM_skin_scRNA, resolution = 1)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 4840
Number of edges: 159696

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9054
Number of communities: 24
Elapsed time: 0 seconds
travis_NM_skin_scRNA <- RunUMAP(travis_NM_skin_scRNA, dims = 1:40)
The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session12:58:23 UMAP embedding parameters a = 0.9922 b = 1.112
12:58:23 Read 4840 rows and found 40 numeric columns
12:58:23 Using Annoy for neighbor search, n_neighbors = 30
12:58:24 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
12:58:24 Writing NN index file to temp file /var/folders/8p/2clwbcfn719f5l1kjsyx4v6s2r9kgj/T//RtmpdfWGXA/file1aa32e12e645
12:58:24 Searching Annoy index using 1 thread, search_k = 3000
12:58:25 Annoy recall = 100%
12:58:26 Commencing smooth kNN distance calibration using 1 thread
12:58:26 Initializing from normalized Laplacian + noise
12:58:27 Commencing optimization for 500 epochs, with 196850 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
12:58:33 Optimization finished

Normal skin - scRNA data from Travis paper

Idents(travis_NM_skin_scRNA) <- "Specific_CellType"
DimPlot(travis_NM_skin_scRNA,pt.size = 2.5,label = TRUE)


Idents(travis_NM_skin_scRNA) <- "CellType"
DimPlot(travis_NM_skin_scRNA,pt.size = 2.5)

save(travis_NM_skin_scRNA,file = "../../TRAVIS_scRNA_DATA/travis_NM_skin_scRNA.RDS")
single_cell.markers <- FindAllMarkers(travis_NM_skin_scRNA,assay = "RNA",logfc.threshold = 0.25)
filtered_single_cell.markers <- single_cell.markers %>% filter(p_val_adj<=0.05) %>% group_by(cluster) %>% top_n(n =300,wt = avg_log2FC) %>% filter(avg_log2FC>0.25)
filtered_spatial_markers <- new.skin.combined.markers %>% filter(p_val_adj<=0.05) %>% group_by(cluster) %>% top_n(n =300,wt = avg_log2FC) %>% filter(avg_log2FC>0.25)

Figure - 2B

##INTERSECT GENES BETWEEN scRNA and Spatial data
st.genes <- unique(rownames(new.skin.combined@assays$Spatial@counts))
sc.genes <- unique(rownames(travis_NM_skin_scRNA@assays$RNA@counts))
all.genes.scrna_and_spt <- unique(intersect(sc.genes,st.genes))
MIA_results <- MIA(total_genes = length(all.genes.scrna_and_spt),single_cell.markers = filtered_single_cell.markers,spatial.markers = filtered_spatial_markers)

E.data <- MIA_results %>% column_to_rownames("cluster")
E.data <- E.data[,order(colnames(E.data))]
pheatmap(E.data,cluster_cols = FALSE,cluster_rows = FALSE,fontsize=15,color = col.pal)
immune_only.E.data <- E.data[,c("T cell-1","T cell-2","T cell-3","Myeloid-1","Langerhans","Mast-1","Mast-2")]
pdf(file = "MIA_regions_IMMUNE_CELLS.pdf",width = 10,height = 4)
pheatmap(immune_only.E.data,cluster_cols = FALSE,cluster_rows = FALSE,fontsize=15,color = col.pal)
dev.off()
structure_only.E_data <- E.data[,c("Fibroblast-1","Fibroblast-2","Fibroblast-4","Fibroblast-5","HairFollicle","Keratinocyte-2","Keratinocyte-3","Keratinocyte-5","Keratinocyte-6","Keratinocyte-8","Sebocyte","Venule-1","Venule-2","Venule-3","Venule-4","VSMC-1")]
pdf(file = "MIA_regions_STRUCTURAL_CELLS.pdf",width = 10,height = 4)
pheatmap(structure_only.E_data,cluster_cols = FALSE,cluster_rows = FALSE,fontsize=15,color = col.pal)
dev.off()

NOW CALCULATING ENRICHMENT USING NEW DATASET (Travis et al)

Seurat based cell type enrichment

# RUN THIS ON BIG PURPLE 
skin_reference.2 <- SCTransform(travis_travis_NM_skin_scRNA, ncells = 3000, verbose = FALSE) %>% RunPCA(verbose = FALSE) %>% 
    RunUMAP(dims = 1:40)
anchors <- FindTransferAnchors(reference = skin_reference.2, query = new.skin.combined, normalization.method = "SCT")
predictions.assay <- TransferData(anchorset = anchors, refdata = skin_reference.2$Specific_CellType, prediction.assay = TRUE, 
    weight.reduction = new.skin.combined[["pca"]],dims = 1:40)
new.skin.combined[["predictions_travis_data"]] <- predictions.assay

CELL TYPES FOR FIGURE 1 - Travis et al. single cell dataset (Only using the healthy subset of scRNA data)

Cell_types <- c("Fibroblast-1","HairFollicle","Keratinocyte-5","Keratinocyte-3","Sebocyte","VSMC-1","Melanocyte")
DefaultAssay(new.skin.combined) <- "predictions_travis_data"
for (x in Cell_types){
  pdf(file = paste("HEALTHY_FEMALE_1_R2_CELL_TYPE_",x,".pdf"),width = 10,height = 15)
  print(SpatialFeaturePlot(new.skin.combined, features = c(x), pt.size.factor = 2.5, ncol = 2, crop = TRUE,images = "HealthyFemale.1.S2") + scale_fill_gradientn(colors=cols,limits = c(0,1))) 
  dev.off()
}

PERCENTAGE PLOT FOR DIFFERENT SPATIAL REGIONS

Calculated on a per sample basis

Regions.df <- table(new.skin.combined@meta.data$Spatial.regions,new.skin.combined@meta.data$orig.ident) %>% as.data.frame() %>% dplyr::rename(Spatial_Region=Var1,Sample=Var2) 

black.bold.16.text <- element_text(face = "bold", color = "black", size = 14,angle = 90, vjust = 0.5, hjust=1)
brks <- c(0, 0.25, 0.5, 0.75, 1)

pdf(file="PERCENTAGE_COMPOSTION_PLOT_HEALTHY_SAMPLES.pdf",height = 14,width = 8)
ggplot(Regions.df,aes(x=Sample,y=Freq,fill=Spatial_Region)) + geom_bar(stat="identity",position="fill") + scale_fill_manual(values =custom_colors)  + ggplot2::theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(),axis.text.x =black.bold.16.text) + scale_y_continuous(breaks = brks, labels = scales::percent(brks)) + ylab("% Composition of Sample by Spatial Region / Clusters")
dev.off()

Cell counts for travis healthy subset data

cell.counts <- as.data.frame(table(travis_NM_skin_scRNA@meta.data$Specific_CellType))
write.csv(cell.counts,file="../../TRAVIS_scRNA_DATA/CELL_COUNTS_TRAVIS_HEALTHY_SKIN_DATA.csv")

Filtered out cell types with less than 50 cells

filtered_cell.counts <- cell.counts %>% filter(Freq>50) 
Idents(travis_NM_skin_scRNA) <- "Specific_CellType"
travis_healthy_data.subset <- subset(x = travis_NM_skin_scRNA, idents = c(filtered_cell.counts$Var1))

DimPlot(travis_healthy_data.subset,pt.size = 2.5)

Plotting final travis healthy data UMAP

pdf(width = 12,height=8,file = "UMAP_TRAVIS_DATA_HEALTHY_SAMPLES_ONLY.pdf")
DimPlot(travis_healthy_data.subset,pt.size = 3.5)
dev.off()

PATHWAY ANALYSIS FOR SPATIAL HEALTHY DATA - PER CLUSTER BASIS

for(i in seq(0,11)){
  cluster <- new.skin.combined.markers %>% filter(cluster==i)
  GO_PATHWAYS_ENRICH(cluster,ONT="BP",OUTPUT = i)
  GO_PATHWAYS_ENRICH(cluster,ONT="CC",OUTPUT = i)
  GO_PATHWAYS_ENRICH(cluster,ONT="MF",OUTPUT = i)
  KEGG_PATHWAYS(cluster,OUTPUT = i)
}

Number of genes used in MIA - (Needed for Venn diagram)

cluster.5 <- filtered_spatial_markers %>% filter(cluster==5)
Myeloid.1 <- filtered_single_cell.markers %>% filter(cluster=="Myeloid-1")

length(intersect(cluster.5$gene,Myeloid.1$gene))

cluster.6 <- filtered_spatial_markers %>% filter(cluster==6)
Keratinocyte.5 <- filtered_single_cell.markers %>% filter(cluster=="Keratinocyte-5")

length(intersect(cluster.6$gene,Keratinocyte.5$gene))

LOAD DATA FROM HANNIFA PAPER

load("../../scRNA_DATA/HEALTHY_SC_RNA_PROCESSED.RData")

UMAP plot for Hannifa healthy skin data

DimPlot(healthy_skin.sc_data,raster = FALSE)

pdf(file = "UMAP_ONLY_HEALTHY_SAMPLES_(HANNIFA_PAPER).pdf",width = 16,height=8)
print(DimPlot(healthy_skin.sc_data_subset,pt.size = 1.2,shuffle = TRUE,raster=FALSE))
dev.off()

Identify marker genes for the pre-assigned clustering results with cell type labels

Idents(healthy_skin.sc_data) <- "final_clustering"
hnf_skin_scRNA.markers <- FindAllMarkers(healthy_skin.sc_data,assay = "RNA",logfc.threshold = 0.25,max.cells.per.ident=400,only.pos = TRUE)

Load MARKER GENES from the saved file for later use

hnf_skin_scRNA.markers <- read.csv("../../scRNA_DATA/HANNIFA_MARKERS.csv") %>% filter(p_val_adj<=0.05) %>% group_by(cluster) %>% top_n(n =300,wt = avg_log2FC) %>% filter(avg_log2FC>0.25)

#SC-DATA - cell counts

hnf_data_counts <- as.data.frame(table(healthy_skin.sc_data@meta.data$final_clustering))
write.csv(hnf_data_counts,file="HEALTHY_SAMPLES_HANNIFA_DATA_COUNTS.csv")

Intersecting genes between ST and scRNA data.

##INTERSECT GENES BETWEEN scRNA and Spatial data
st.genes <- unique(rownames(new.skin.combined@assays$Spatial@counts))
sc.genes <- unique(rownames(healthy_skin.sc_data@assays$RNA@counts))
all.genes.scrna_and_spt <- unique(intersect(sc.genes,st.genes))

MIA FOR HANNIFA PAPER - healthy samples data only

MIA_results_PART_2 <- MIA(total_genes = length(all.genes.scrna_and_spt),single_cell.markers = hnf_skin_scRNA.markers,spatial.markers = filtered_spatial_markers)

E.data_PART_2 <- MIA_results_PART_2 %>% column_to_rownames("cluster")
E.data_PART_2 <- E.data_PART_2[,order(colnames(E.data_PART_2))]
is.na(E.data_PART_2) <- do.call(cbind,lapply(E.data_PART_2, is.infinite))
pheatmap(E.data_PART_2,cluster_cols = FALSE,cluster_rows = FALSE,fontsize=15,color = col.pal)

For Immune populations

## IMMUNE CELLS
immune_only.E.data_PART_2 <- E.data_PART_2[,c("DC1","DC2","Macro_1","Macro_2","moDC_1","moDC_2","moDC_3","MigDC","Mono","Inf_mono","ILC1_NK","ILC1_3","ILC2","Tc","Th","Treg","Mast_cell","Plasma","NK")]
pdf(file = "MIA_regions_(HANNIFA_PAPER)_IMMUNE_CELLS.pdf",width = 10,height = 5)
print(pheatmap(immune_only.E.data_PART_2,cluster_cols = FALSE,cluster_rows = FALSE,fontsize=15,color = col.pal))
dev.off()

For non-immune populations

non_immune_only.E.data_PART_2 <- E.data_PART_2 %>% dplyr::select(-c("DC1","DC2","Macro_1","Macro_2","moDC_1","moDC_2","moDC_3","MigDC","Mono","Inf_mono","ILC1_NK","ILC1_3","ILC2","Tc","Th","Treg","Mast_cell","Plasma","NK","nan"))
pdf(file = "MIA_regions_(HANNIFA_PAPER)_NON_IMMUNE_CELLS.pdf",width = 10,height = 5)
print(pheatmap(non_immune_only.E.data_PART_2,cluster_cols = FALSE,cluster_rows = FALSE,fontsize=15,color = col.pal))
dev.off()
#VIOLIN PLOT FOR UMIs and SEURAT CLUSTERS
pdf(file = "VIOLIN_PLOT_UMIs_and_CLUSTERS_HEALTHY_SAMPLES.pdf",width = 16,height=12)
print(VlnPlot(new.skin.combined,group.by = "seurat_clusters",features = "nCount_Spatial",cols = custom_colors))
dev.off()

# LOG TRANSFORMED UMI COUNTS
pdf(file = "VIOLIN_PLOT_UMIs_and_CLUSTERS_HEALTHY_SAMPLES(LOG_TRANSFORMED).pdf",width = 16,height=12)
print(VlnPlot(new.skin.combined,group.by = "seurat_clusters",features = "nCount_Spatial",cols = custom_colors,log = TRUE))
dev.off()
# SPOT FREQUENCY TABLE - BY SPATIAL REGION
spatial.freq <- as.data.frame(table(new.skin.combined@meta.data$Spatial.regions))
write.csv(spatial.freq,file="SPATIAL_REGIONS_CLUSTERS_SPOT_COUNTS.csv")

QC FIGURES - Replotting

Supplementary figure - 2

# HEALTHY FEMALE SKIN 2
#REMOVE SPOTS
HEALTHY.Female1.s3 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HF-1/",slice="HealthyFemale-1-S3")

## HEALTHY FEMALE
HEALTHY.Female2.s1 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HF-2E/",slice="HealthyFemale-2-S1")
HEALTHY.Female2.s2 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HF-2F/",slice="HealthyFemale-2-S2")

#HEALATHY MALE
HEALTHY.Male.s2 <- Load10X_Spatial(data.dir ="../../SEVENTH RUN/ST-HM-1/",slice="HealthyMale-1-S2")
remove.spots <- read.csv(file="../../CLOUPE_FILES/SEVENTH_RUN/HF-1-SP/remove.csv")
subset_spots <- Cells(HEALTHY.Female1.s3)[which((!(rownames(HEALTHY.Female1.s3@meta.data) %in% remove.spots$Barcode)))]
HEALTHY.Female1.s3.clean <- subset(HEALTHY.Female1.s3,cells=subset_spots)

pdf(width = 8,height=10,file = "HV2_SP_SPATIAL_PLOT(UNFILTERED).pdf")
print(SpatialDimPlot(HEALTHY.Female1.s3.clean,pt.size.factor = 2,group.by = "orig.ident"))
dev.off()

pdf(width = 8,height=10,file = "HV2_SP_SPATIAL_PLOT(FILTERED).pdf")
print(SpatialDimPlot(new.skin.combined,images = "HealthyFemale.1.S3",pt.size.factor = 2,group.by = "orig.ident"))
dev.off()
remove.spots <- read.csv(file="../../CLOUPE_FILES/SEVENTH_RUN/HF-2-SE/Remove.csv")
subset_spots <- Cells(HEALTHY.Female2.s1)[which((!(rownames(HEALTHY.Female2.s1@meta.data) %in% remove.spots$Barcode)))]
HEALTHY.Female2.s1.clean <- subset(HEALTHY.Female2.s1,cells=subset_spots)

pdf(width = 8,height=10,file = "HV3_SE_SPATIAL_PLOT(UNFILTERED).pdf")
print(SpatialDimPlot(HEALTHY.Female2.s1.clean,pt.size.factor = 2,group.by = "orig.ident"))
dev.off()

pdf(width = 8,height=10,file = "HV3_SE_SPATIAL_PLOT(FILTERED).pdf")
print(SpatialDimPlot(new.skin.combined,images = "HealthyFemale.2.S1",pt.size.factor = 2,group.by = "orig.ident"))
dev.off()
remove.spots <- read.csv(file="../../CLOUPE_FILES/SEVENTH_RUN/HF-2-SP/Remove.csv")
subset_spots <- Cells(HEALTHY.Female2.s2)[which((!(rownames(HEALTHY.Female2.s2@meta.data) %in% remove.spots$Barcode)))]
HEALTHY.Female2.s2.clean <- subset(HEALTHY.Female2.s2,cells=subset_spots)

pdf(width = 8,height=10,file = "HV3_SP_SPATIAL_PLOT(UNFILTERED).pdf")
print(SpatialDimPlot(HEALTHY.Female2.s2.clean,pt.size.factor = 2,group.by = "orig.ident"))
dev.off()

pdf(width = 8,height=10,file = "HV3_SP_SPATIAL_PLOT(FILTERED).pdf")
print(SpatialDimPlot(new.skin.combined,images = "HealthyFemale.2.S2",pt.size.factor = 2,group.by = "orig.ident"))
dev.off()
remove.spots <- read.csv(file="../../CLOUPE_FILES/SEVENTH_RUN/HM-SP-2/remove.csv")
subset_spots <- Cells(HEALTHY.Male.s2)[which((!(rownames(HEALTHY.Male.s2@meta.data) %in% remove.spots$Barcode)))]
HEALTHY.Male.s2.clean <- subset(HEALTHY.Male.s2,cells=subset_spots)

pdf(width = 8,height=10,file = "HV1_SP_R2_SPATIAL_PLOT(UNFILTERED).pdf")
print(SpatialDimPlot(HEALTHY.Male.s2.clean,pt.size.factor = 2.2,group.by = "orig.ident"))
dev.off()

pdf(width = 8,height=10,file = "HV1_SP_R2_SPATIAL_PLOT(FILTERED).pdf")
print(SpatialDimPlot(new.skin.combined,images = "HealthyMale.1.S2",pt.size.factor = 2.2,group.by = "orig.ident"))
dev.off()

Import the spots to be removed from loupe browser.

remove.spots <- read.csv(file="../../FIFTH_RUN/SAMPLE D1/REMOVE.csv")
subset_spots <- Cells(HEALTHY.Female1.s2)[which((!(rownames(HEALTHY.Female1.s2@meta.data) %in% remove.spots$Barcode)))]
HEALTHY.Female1.s2.clean <- subset(HEALTHY.Female1.s2,cells=subset_spots)
SpatialDimPlot(HEALTHY.Female.s2.clean)
SpatialDimPlot(HEALTHY.Female1.s2.clean)

pdf(width = 8,height=10,file = "HV2_SP_R2_SPATIAL_PLOT(UNFILTERED).pdf")
print(SpatialDimPlot(HEALTHY.Female1.s2.clean,pt.size.factor = 2.2,group.by = "orig.ident"))
dev.off()

pdf(width = 8,height=10,file = "HV2_SP_R2_SPATIAL_PLOT(FILTERED).pdf")
print(SpatialDimPlot(new.skin.combined,images = "HealthyFemale.1.S2",pt.size.factor = 2.2,group.by = "orig.ident"))
dev.off()

AVERAGE GENE COUNTS

Idents(new.skin.combined) <- "seurat_clusters"

clusters <- unique(new.skin.combined@meta.data$seurat_clusters) %>% as.vector()

for(x in clusters){
  avg_exp.cluster <- AverageExpression(new.skin.combined,slot = "counts",assay="Spatial") %>% as.data.frame() %>% dplyr::select(paste("Spatial.",x,sep = "")) %>% filter(x>0) %>% write.csv(file = paste("CLUSTER_",x,"_GENE_COUNTS.csv",sep = ""))
}
avg_exp.all_clusters <- AverageExpression(new.skin.combined,slot = "counts",assay="Spatial") %>% as.data.frame()
write.csv(avg_exp.all_clusters,file="ALL_CLUSTERS_GENE_COUNTS.csv")

avg_exp.cluster_4 <- AverageExpression(new.skin.combined,slot = "counts",assay="Spatial") %>% as.data.frame() %>% dplyr::select("Spatial.4.Hypodermis") %>% filter(Spatial.4.Hypodermis>0)
write.csv(avg_exp.cluster_4,file="CLUSTER_4_GENE_COUNTS.csv")
avg_exp.cluster_2 <- AverageExpression(new.skin.combined,slot = "counts",assay="Spatial") %>% as.data.frame() %>% dplyr::select("Spatial.2.Dermis.adipose") %>% filter(Spatial.2.Dermis.adipose>0)
write.csv(avg_exp.cluster_2,file="CLUSTER_2_GENE_COUNTS.csv")

HANNIFA DATA - NEW UMAP

healthy_skin.sc_data <- FindNeighbors(healthy_skin.sc_data, dims = 1:40)
healthy_skin.sc_data <- FindClusters(healthy_skin.sc_data, verbose = FALSE,resolution = 1)
healthy_skin.sc_data <- RunUMAP(healthy_skin.sc_data, dims = 1:40)
Idents(healthy_skin.sc_data) <- "final_clustering"
healthy_skin.sc_data <- subset(healthy_skin.sc_data,idents = c("nan"),invert=TRUE)
pdf(width = 12,height=8,file = "UMAP_HANNIFA_DATA_HEALTHY_SAMPLES_ONLY.pdf")
DimPlot(healthy_skin.sc_data,pt.size = 3.5,raster=FALSE)
dev.off()

SINGLE CELL DATA - ENRICHMENT PLOTS (USING ONLY ONE HEALTHY SAMPLE)

HEALTHY.Female1.s2.clean<- st_filter_by_genes(st.data = HEALTHY.Female1.s2.clean,x = 200)
HEALTHY.Female1.s2.clean <- SCTransform(HEALTHY.Female1.s2.clean, verbose = FALSE,assay="Spatial")
HEALTHY.Female1.s2.clean <- RunPCA(HEALTHY.Female1.s2.clean)
#travis_NM_skin_scRNA <- readRDS(file="../../TRAVIS_scRNA_DATA/travis_NM_skin_scRNA.RDS")
# RUN THIS ON BIG PURPLE 
skin_reference.3 <- SCTransform(travis_NM_skin_scRNA, ncells = 3000, verbose = FALSE) %>% RunPCA(verbose = FALSE) %>% 
    RunUMAP(dims = 1:40)
iteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedNaNs producediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachediteration limit reachedThe default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session15:43:15 UMAP embedding parameters a = 0.9922 b = 1.112
15:43:15 Read 4840 rows and found 40 numeric columns
15:43:15 Using Annoy for neighbor search, n_neighbors = 30
15:43:15 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
15:43:15 Writing NN index file to temp file /var/folders/8p/2clwbcfn719f5l1kjsyx4v6s2r9kgj/T//Rtmpovk9y0/filefd7577fa79e5
15:43:15 Searching Annoy index using 1 thread, search_k = 3000
15:43:16 Annoy recall = 100%
15:43:17 Commencing smooth kNN distance calibration using 1 thread
15:43:18 Initializing from normalized Laplacian + noise
15:43:19 Commencing optimization for 500 epochs, with 191228 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
15:43:25 Optimization finished
anchors <- FindTransferAnchors(reference = skin_reference.3, query = HEALTHY.Female1.s2.clean, normalization.method = "SCT")
Normalizing query using reference SCT model
Adding image data that isn't associated with any assay presentPerforming PCA on the provided reference using 2702 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 530 anchors
predictions.assay <- TransferData(anchorset = anchors, refdata = skin_reference.3$Specific_CellType, prediction.assay = TRUE, 
    weight.reduction = HEALTHY.Female1.s2.clean[["pca"]],dims = 1:40)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
HEALTHY.Female1.s2.clean[["predictions_travis_data"]] <- predictions.assay
library(RColorBrewer)
SpatialColors <- colorRampPalette(colors = rev(x = brewer.pal(n = 11, name = "Spectral")))
cols <- SpatialColors(n = 100)
SpatialFeaturePlot(HEALTHY.Female1.s2.clean,features = c("Melanocyte"), pt.size.factor = 2.5)+ scale_fill_gradientn(colors=cols,limits = c(0,1.000001))
Could not find Melanocyte in the default search locations, found in predictions_travis_data assay instead`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

SpatialFeaturePlot(HEALTHY.Female1.s2.clean,features = c("VSMC-1"), pt.size.factor = 2.5)+ scale_fill_gradientn(colors=cols,limits = c(0,1.000001))
Could not find VSMC-1 in the default search locations, found in predictions_travis_data assay instead`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

SpatialFeaturePlot(HEALTHY.Female1.s2.clean,features = c("HairFollicle"), pt.size.factor = 2.5)+ scale_fill_gradientn(colors=cols,limits = c(0,1.000001))
Could not find HairFollicle in the default search locations, found in predictions_travis_data assay instead`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

SpatialFeaturePlot(HEALTHY.Female1.s2.clean,features = c("Keratinocyte-5"), pt.size.factor = 2.5)+ scale_fill_gradientn(colors=cols,limits = c(0,1.000001))
Could not find Keratinocyte-5 in the default search locations, found in predictions_travis_data assay instead`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

SpatialFeaturePlot(HEALTHY.Female1.s2.clean,features = c("Sebocyte"), pt.size.factor = 2.5)+ scale_fill_gradientn(colors=cols,limits = c(0,1.000001))
Could not find Sebocyte in the default search locations, found in predictions_travis_data assay instead`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIyBSIE5vdGVib29rIGNvdmVyaW5nIGRhdGEgZ2VuZXJhdGVkIGZyb20gaGVhbHRoeSBzYW1wbGVzIGZvciBGaWd1cmUgMSwgU3VwcGxlbWVudGFyeSBmaWd1cmUgMSBhbmQgMi4KIyMgTE9BRCBBTEwgUEFDS0FHRVMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShzY2FsZXMpCmBgYAojIEltcG9ydCBmdW5jdGlvbnMgZnJvbSB0aGUgY3VzdG9tIFIgc2NyaXB0CmBgYHtyfQpzb3VyY2UoIlNQQVRJQUxfRlVOQ1RJT05TLlIiKQpgYGAKCiMgSU1QT1JUSU5HIFRIRSBIRUFUTFRIWSBTQU1QTEVTCmBgYHtyfQojIyBIRUFMVEhZIFNBTVBMRVMKIyMgSEVBTFRIWSBNQUxFIFNLSU4gMSAmIDIKSEVBTFRIWS5NYWxlLnMxIDwtIExvYWQxMFhfU3BhdGlhbChkYXRhLmRpciA9Ii4uLy4uL0ZPVVJUSF9SVU4vU0FNUExFIEExLyIsc2xpY2U9IlNULUhNLTEtUjEiKQpIRUFMVEhZLk1hbGUuczIgPC0gTG9hZDEwWF9TcGF0aWFsKGRhdGEuZGlyID0iLi4vLi4vU0VWRU5USCBSVU4vU1QtSE0tMS8iLHNsaWNlPSJTVC1ITS0xLVIyIikKCiMjIEhFQUxUSFkgRkVNQUxFIFNLSU4gMSAmIDIgKEZST00gVEhFIFNBTUUgRE9OT1IpCkhFQUxUSFkuRmVtYWxlMS5zMSA8LSBMb2FkMTBYX1NwYXRpYWwoZGF0YS5kaXIgPSIuLi8uLi9GT1VSVEhfUlVOL1NBTVBMRSBCMS8iLHNsaWNlPSJTVC1IRi0xLVIxIikKSEVBTFRIWS5GZW1hbGUxLnMyIDwtIExvYWQxMFhfU3BhdGlhbChkYXRhLmRpciA9Ii4uLy4uL0ZJRlRIX1JVTi9TQU1QTEUgRDEvIixzbGljZT0iU1QtSEYtMS1SMiIpCkhFQUxUSFkuRmVtYWxlMS5zMyA8LSBMb2FkMTBYX1NwYXRpYWwoZGF0YS5kaXIgPSIuLi8uLi9TRVZFTlRIIFJVTi9TVC1IRi0xLyIsc2xpY2U9IlNULUhGLTEtUjMiKQoKIyMgSEVBTFRIWSBGRU1BTEUKSEVBTFRIWS5GZW1hbGUyLnMxIDwtIExvYWQxMFhfU3BhdGlhbChkYXRhLmRpciA9Ii4uLy4uL1NFVkVOVEggUlVOL1NULUhGLTJFLyIsc2xpY2U9IlNULUhGLTItUjEiKQpIRUFMVEhZLkZlbWFsZTIuczIgPC0gTG9hZDEwWF9TcGF0aWFsKGRhdGEuZGlyID0iLi4vLi4vU0VWRU5USCBSVU4vU1QtSEYtMkYvIixzbGljZT0iU1QtSEYtMi1SMiIpCgpgYGAKCiMjIyBJbXBvcnQgdGhlIHNwb3RzIHRvIGJlIHJlbW92ZWQgZnJvbSBsb3VwZSBicm93c2VyLgpgYGB7cn0KIyBIRUFMVEhZIEZFTUFMRSBTS0lOIDIKI1JFTU9WRSBTUE9UUwoKcmVtb3ZlLnNwb3RzIDwtIHJlYWQuY3N2KGZpbGU9Ii4uLy4uL0NMT1VQRV9GSUxFUy9GSUZUSF9SVU4vRDEvT1VUTElFUlMuY3N2IikKc3Vic2V0X3Nwb3RzIDwtIENlbGxzKEhFQUxUSFkuRmVtYWxlMS5zMilbd2hpY2goKCEocm93bmFtZXMoSEVBTFRIWS5GZW1hbGUxLnMyQG1ldGEuZGF0YSkgJWluJSByZW1vdmUuc3BvdHMkQmFyY29kZSkpKV0KSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuIDwtIHN1YnNldChIRUFMVEhZLkZlbWFsZTEuczIsY2VsbHM9c3Vic2V0X3Nwb3RzKQpgYGAKCiNTQU1QTEUgSURTCmBgYHtyfQoKSEVBTFRIWS5NYWxlLnMxJHNhbXBsZS5pZDwtICJIVjFfUzFfUjEiIApIRUFMVEhZLk1hbGUuczIkc2FtcGxlLmlkPC0gIkhWMV9TMV9SMiIKCkhFQUxUSFkuRmVtYWxlMS5zMSRzYW1wbGUuaWQgPC0gIkhWMl9TMV9SMSIKSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuJHNhbXBsZS5pZCA8LSAiSFYyX1MxX1IyIgpIRUFMVEhZLkZlbWFsZTEuczMkc2FtcGxlLmlkIDwtICJIVjJfUzIiCgpIRUFMVEhZLkZlbWFsZTIuczEkc2FtcGxlLmlkIDwtICJIVjNfUzEiCkhFQUxUSFkuRmVtYWxlMi5zMiRzYW1wbGUuaWQgPC0gIkhWM19TMiIKYGBgCgojIFNBTVBMRSBJRFMgKHZlcnNpb24gMikgLSAoRnVsbCBuYW1lICsgQmlvcHN5IHNpdGUpCiMgVFJVTksgYW5kIEZBIChGb3JlYXJtKQpgYGB7cn0KSEVBTFRIWS5NYWxlLnMxJG9yaWcuaWRlbnQgPC0gIkhlYWx0aHkgVm9sdW50ZWVyIDEgLSBUUlVOSyBSMSIgCkhFQUxUSFkuTWFsZS5zMiRvcmlnLmlkZW50IDwtIkhlYWx0aHkgVm9sdW50ZWVyIDEgLSBUUlVOSyBSMiIKCkhFQUxUSFkuRmVtYWxlMS5zMSRvcmlnLmlkZW50IDwtICJIZWFsdGh5IFZvbHVudGVlciAyIC0gRkEgUjEiCkhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbiRvcmlnLmlkZW50IDwtICJIZWFsdGh5IFZvbHVudGVlciAyIC0gRkEgUjIiCkhFQUxUSFkuRmVtYWxlMS5zMyRvcmlnLmlkZW50IDwtICJIZWFsdGh5IFZvbHVudGVlciAyIC0gVFJVTksiCgpIRUFMVEhZLkZlbWFsZTIuczEkb3JpZy5pZGVudCA8LSAiSGVhbHRoeSBWb2x1bnRlZXIgMyAtIEZBIFIxIgpIRUFMVEhZLkZlbWFsZTIuczIkb3JpZy5pZGVudCA8LSAiSGVhbHRoeSBWb2x1bnRlZXIgMyAtIFRSVU5LIgpgYGAKCgojIENvbXBpbGUgdGhlIHNhbXBsZXMgaW50byBvbmUgbGlzdC4KYGBge3J9CkhlYWx0aHlfU2FtcGxlcyA8LSBjKEhFQUxUSFkuTWFsZS5zMSxIRUFMVEhZLk1hbGUuczIsSEVBTFRIWS5GZW1hbGUxLnMxLEhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbixIRUFMVEhZLkZlbWFsZTEuczMsSEVBTFRIWS5GZW1hbGUyLnMxLEhFQUxUSFkuRmVtYWxlMi5zMikKYGBgCgojIEdlbmVyYXRpbmcgc3BhdGlhbCBwbG90cyB3aXRob3V0IFFDIGZpbHRlcmluZwpgYGB7cn0KZm9yICh4IGluIEhlYWx0aHlfU2FtcGxlcyl7CiAgc3RfcGxvdCh4KQp9CmBgYAoKIyBRQyBwbG90cyBmb3IgaGVhbHRoeSBzYW1wbGVzCmBgYHtyfQpmb3IgKHggaW4gSGVhbHRoeV9TYW1wbGVzKXsKICBzdF9wbG90X1FDKHgpCn0KYGBgCgojIFFDIHNjYXR0ZXIgcGxvdHMKYGBge3J9CmZvciAoeCBpbiBIZWFsdGh5X1NhbXBsZXMpewogIHN0X3NjYXR0ZXJfUUMoeCkKfQpgYGAKCiMgRmlsdGVyaW5nIGFsbCBzYW1wbGVzIHRvIHJlbW92ZSBzcG90cyB3aXRoIGxlc3MgdGhhbiAyMDAgZ2VuZXMgZXhwcmVzc2VkCmBgYHtyfQppIDwtIDEKd2hpbGUoaSA8PSBsZW5ndGgoSGVhbHRoeV9TYW1wbGVzKSl7CiAgZmlsdGVyZWRfZGF0YSA8LSBzdF9maWx0ZXJfYnlfZ2VuZXMoc3QuZGF0YSA9IEhlYWx0aHlfU2FtcGxlc1tbaV1dLHggPSAyMDApCiAgSGVhbHRoeV9TYW1wbGVzW1tpXV0gPC0gZmlsdGVyZWRfZGF0YQogIGkgPC0gaSsxCn0KYGBgCgojIEJhdGNoIGNvcnJlY3Rpb24gb2YgYWxsIHNhbXBsZXMgdXNpbmcgU2V1cmF0IEFuY2hvciBpbnRlZ2VyYXRpb24KYGBge3J9Cm5ldy5za2luLmNvbWJpbmVkIDwtIHN0X2NvbWJpbmUoSGVhbHRoeV9TYW1wbGVzLG5kaW0gPSAyMCxyZXMgPSAwLjYpCmBgYAoKIyBBRERJTkcgQURESVRJT05BTCBNRVRBLURBVEEKYGBge3IsZXZhbD1GQUxTRX0KbWV0YS5kYXRhX3NraW4gPC0gbmV3LnNraW4uY29tYmluZWRAbWV0YS5kYXRhJG9yaWcuaWRlbnQgJT4lIGFzLmRhdGEuZnJhbWUoKQp3cml0ZS5jc3YobWV0YS5kYXRhX3NraW4sZmlsZT0iSEVBTFRIWV9TQU1QTEVTX1NUX01FVEFfREFUQS5jc3YiKQpgYGAKCiMgSU1QT1JUSU5HIFNUIE1FVEEtREFUQSBVUERBVEVEIFZFUlNJT04KYGBge3IsZXZhbD1GQUxTRX0KbWV0YS5kYXRhX3NraW5fdXBkYXRlZCA8LSByZWFkLmNzdihmaWxlPSJIRUFMVEhZX1NBTVBMRVNfU1RfTUVUQV9EQVRBLmNzdiIpCmBgYAoKIyBBRERJTkcgTUVUQS1EQVRBIHRvIFNldXJhdCBvYmplY3QKYGBge3IsZXZhbD1GQUxTRX0KbmV3LnNraW4uY29tYmluZWRAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPC0gbWV0YS5kYXRhX3NraW5fdXBkYXRlZCRvcmlnLmlkZW50Cm5ldy5za2luLmNvbWJpbmVkQG1ldGEuZGF0YSRzYW1wbGUuaWQgPC0gbWV0YS5kYXRhX3NraW5fdXBkYXRlZCRzYW1wbGUuaWQKYGBgCgojIERldGVybWluaW5nIG1hcmtlciBnZW5lcyBmb3IgYmF0Y2ggY29ycmVjdGVkIGhlYWx0aHkgc2FtcGxlcyArIGhlYXRtYXAKYGBge3J9Cm5ldy5za2luLmNvbWJpbmVkLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMobmV3LnNraW4uY29tYmluZWQsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsYXNzYXkgPSAiU0NUIikKRGVmYXVsdEFzc2F5KG5ldy5za2luLmNvbWJpbmVkKSA8LSAiU0NUIgp0b3AxMCA8LSBuZXcuc2tpbi5jb21iaW5lZC5tYXJrZXJzICU+JQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgICBmaWx0ZXIocF92YWxfYWRqPDAuMDUpICU+JQogICAgdG9wX24obiA9IDEwLCB3dCA9IGF2Z19sb2cyRkMpICU+JQogICAgZmlsdGVyKGdlbmUgJWluJSBWYXJpYWJsZUZlYXR1cmVzKG5ldy5za2luLmNvbWJpbmVkX1YyKSkKcGRmKHdpZHRoID0gMjAsaGVpZ2h0PTE1LGZpbGUgPSAiSEVBVE1BUF9IRUFMVEhZX1NBTVBMRVNfQ0xVU1RFUlNfT05MWS5wZGYiKQpwcmludChEb0hlYXRtYXAobmV3LnNraW4uY29tYmluZWQsIGZlYXR1cmVzID0gdG9wMTAkZ2VuZSxhc3NheSA9ICJTQ1QiLGdyb3VwLmNvbG9ycyA9IGN1c3RvbV9jb2xvcnMpICsgTm9MZWdlbmQoKSkKZGV2Lm9mZigpCmBgYAoKIyBBc3NpZ24gY2x1c3RlciBpZHMgCmBgYHtyfQpuZXcuY2x1c3Rlci5pZHMgPC0gYygiMCBNaXhlZCIsIjEgRGVybWlzIiwKIjIgRGVybWlzIEFkaXBvc2UiLCIzIEVwaWRlcm1pcyAxIiwiNCBEZXJtaXMgQ29ubmVjdGl2ZSBUaXNzdWUiLCI1IFVwcGVyIGZvbGxpY2xlIChVRikgYW5kIFBlcmlmb2xsaWN1bGFyIGRlcm1pcyIsIjYgRXBpZGVybWlzIDIiLCI3IERlcm1pcyAyIiwiOCBEZXJtaXMgU21vb3RoIE11c2NsZSIsIjkgSGFpciBmb2xsaWNsZSIsIjEwIERlcm1pcyBMeW1waGF0aWNzIiwiMTEgRGVybWlzIHZhc2N1bGF0dXJlIikKbmFtZXMobmV3LmNsdXN0ZXIuaWRzKSA8LSBsZXZlbHMobmV3LnNraW4uY29tYmluZWQpCm5ldy5za2luLmNvbWJpbmVkIDwtIFJlbmFtZUlkZW50cyhuZXcuc2tpbi5jb21iaW5lZCwgbmV3LmNsdXN0ZXIuaWRzKQpuZXcuc2tpbi5jb21iaW5lZCA8LSBTdGFzaElkZW50KG5ldy5za2luLmNvbWJpbmVkLCBzYXZlLm5hbWUgPSAiU3BhdGlhbC5yZWdpb25zIikKYGBgCgojIERlZmluaW5nIGFuZCB2aWV3aW5nIGNvbG9yIHNjaGVtZSBmb3IgVU1BUCBhbmQgc3BhdGlhbCBwbG90CmBgYHtyfQpjdXN0b21fY29sb3JzIDwtIGMoIiNCNERGRkMiLCIjNkVBQjNEIiwiI0ZGRDcwMCIsIiNBMDIwRjAiLCIjRkZBNTAwIiwiI0FFREQzQyIsIiM1OTU5NTkiLCIjRDJBRjgxRkYiLCIjM0E0OUZDIiwiI0ZGMDAwMCIsIiNBODZGM0QiLCIjQTE4RkFBIikKc2hvd19jb2woY3VzdG9tX2NvbG9ycykKYGBgCgojIEdlbmVyYWwgVU1BUCB3aXRoIGRlZmluZWQgY29sb3Igc2NoZW1lCmBgYHtyfQpwZGYod2lkdGggPSAxMixoZWlnaHQ9OCxmaWxlID0gIlVNQVBfSEVBTFRIWV9TQU1QTEVTX0NMVVNURVJTX09OTFkucGRmIikKRGltUGxvdChuZXcuc2tpbi5jb21iaW5lZCxjb2xzID0gY3VzdG9tX2NvbG9ycyxwdC5zaXplID0gMy41KQpkZXYub2ZmKCkKCiMgRk9SIElOIE5PVEVCT09LIFZJRVcKRGltUGxvdChuZXcuc2tpbi5jb21iaW5lZCxjb2xzID0gY3VzdG9tX2NvbG9ycyxwdC5zaXplID0gMy41KQpgYGAKCiMgVU1BUCBwbG90IHNwbGl0IGJ5IHNhbXBsZXMKYGBge3J9CkRpbVBsb3QobmV3LnNraW4uY29tYmluZWQsc3BsaXQuYnkgPSAic2FtcGxlLmlkIikKYGBgCgpgYGB7cn0KIyMgU0FWRSBUSEUgUkVTVUxUUwpzYXZlKG5ldy5za2luLmNvbWJpbmVkLGZpbGUgPSAiSEVBTFRIWV9TS0lOX1NBTVBMRVNfU1QuUkRhdGEiKQpgYGAKCiMgU3BhdGlhbCBwbG90IGZvciBIVjJfUzJfUjEgL0hFQUxUSFlfRkVNQUxFX1NBTVBMRV8xCiMgU0FWRSBPVVRQVVQgVE8gUERGCmBgYHtyfQpwZGYod2lkdGggPSA4LGhlaWdodD0xMCxmaWxlID0gIkhFQUxUSFlfRkVNQUxFX1NBTVBMRV8xX1IyX1NQQVRJQUxfUExPVC5wZGYiKQpTcGF0aWFsRGltUGxvdChuZXcuc2tpbi5jb21iaW5lZCxpbWFnZXM9IkhlYWx0aHlGZW1hbGUuMS5TMiIsY29scyA9IGN1c3RvbV9jb2xvcnMscHQuc2l6ZS5mYWN0b3IgPSAyLjQpCmRldi5vZmYoKQpgYGAKCiMgVklFVyBTUEFUSUFMIFBMT1QgSEVSRQpgYGB7cn0KU3BhdGlhbERpbVBsb3QobmV3LnNraW4uY29tYmluZWQsaW1hZ2VzPSJIZWFsdGh5RmVtYWxlLjEuUzIiLGNvbHMgPSBjdXN0b21fY29sb3JzLHB0LnNpemUuZmFjdG9yID0gMi40KQpgYGAKCiMgR2VuZXJhdGUgU3BhdGlhbCBwbG90IGZvciBhbGwgc2FtcGxlcwpgYGB7cn0KaW1hZ2VzIDwtIEltYWdlcyhuZXcuc2tpbi5jb21iaW5lZCkgJT4lIGFzLnZlY3RvcigpCmZvcih4IGluIGltYWdlcyl7CiAgcGRmKHdpZHRoID0gOCxoZWlnaHQ9MTAsZmlsZSA9IHBhc3RlKHgsIl9TUEFUSUFMX1BMT1QucGRmIikpCiAgcHJpbnQoU3BhdGlhbERpbVBsb3QobmV3LnNraW4uY29tYmluZWQsaW1hZ2VzPXgsY29scyA9IGN1c3RvbV9jb2xvcnMscHQuc2l6ZS5mYWN0b3IgPSAyKSkKICBkZXYub2ZmKCkKfQpgYGAKCiMgQ29sb3Igc2NoZW1lIGZvciBNSUEgaGVhdG1hcApgYGB7cn0KY29sLnBhbCA8LSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoOSwgIk9yUmQiKQpgYGAKCiMjIE1JQSAtIHNjUk5BIGRhdGFzZXQgKFRyYXZpcyBldCBhbCkKIyMgU0lOR0xFIENFTEwgREFUQSBGUk9NIFRSQVZJUyBQQVBFUgpgYGB7cn0KbG9hZCgiLi4vLi4vVFJBVklTX3NjUk5BX0RBVEEvU2tpblNldXJhdFRvdGFsLlJkYXRhIikKYGBgCgpgYGB7cn0KIyBNRVRBIERBVEEgRlJPTSBUUkFWSVMgCm1ldGEuZGF0YSA8LSByZWFkLmNzdigiLi4vLi4vVFJBVklTX3NjUk5BX0RBVEEvQ2VsbF9MZXZlbF9NZXRhZGF0YS5jc3YiKQpgYGAKCmBgYHtyfQojQWRkTWV0YURhdGEoU2tpblNldXJhdFRvdGFsLG1ldGFkYXRhID0gbWV0YS5kYXRhJFNwZWNpZmljX0NlbGxUeXBlLGNvbC5uYW1lID0gIlNwZWNpZmljX0NlbGx0eXBlIikKc2tpbi5tZXRhLmRhdGEgPC0gYXMuZGF0YS5mcmFtZShTa2luU2V1cmF0VG90YWxAbWV0YS5kYXRhKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJDZWxsSUQiKQppbm5lcl9qb2luKHg9c2tpbi5tZXRhLmRhdGEseT1tZXRhLmRhdGEsYnk9IkNlbGxJRCIpCmBgYApgYGB7cn0KU2tpblNldXJhdFRvdGFsQG1ldGEuZGF0YSA8LSBpbm5lcl9qb2luKHg9c2tpbi5tZXRhLmRhdGEseT1tZXRhLmRhdGEsYnk9IkNlbGxJRCIpICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoIkNlbGxJRCIpCmBgYAoKCmBgYHtyLGV2YWw9RkFMU0V9ClNraW5TZXVyYXRUb3RhbEBtZXRhLmRhdGEkQ2VsbHR5cGUgPC0gbWV0YS5kYXRhJENlbGxUeXBlClNraW5TZXVyYXRUb3RhbEBtZXRhLmRhdGEkQ29uZGl0aW9uIDwtIG1ldGEuZGF0YSRDb25kaXRpb24KU2tpblNldXJhdFRvdGFsQG1ldGEuZGF0YSRDZWxsdHlwZV9zcGVjaWZpYyA8LSBtZXRhLmRhdGEkU3BlY2lmaWMKU2tpblNldXJhdFRvdGFsQG1ldGEuZGF0YSRTYW1wbGVJRCA8LSBtZXRhLmRhdGEkU2FtcGxlQ29uZGl0aW9uCmBgYAoKYGBge3J9CiNTVUJTRVQgREFUQSBUTyBPTkxZIEhFQUxUSFkgU0FNUExFUwp0cmF2aXNfTk1fc2tpbl9zY1JOQTwtIHN1YnNldChTa2luU2V1cmF0VG90YWwsc3Vic2V0ID0gQ29uZGl0aW9uID09IGMoIk5vcm1hbCIpKQpgYGAKCgpgYGB7cn0KIyMgUFJPQ0VTUyBTQyBSTkEgREFUQQp0cmF2aXNfTk1fc2tpbl9zY1JOQSA8LSBOb3JtYWxpemVEYXRhKHRyYXZpc19OTV9za2luX3NjUk5BKQp0cmF2aXNfTk1fc2tpbl9zY1JOQSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyh0cmF2aXNfTk1fc2tpbl9zY1JOQSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQp0cmF2aXNfTk1fc2tpbl9zY1JOQSA8LSBTY2FsZURhdGEodHJhdmlzX05NX3NraW5fc2NSTkEpCnRyYXZpc19OTV9za2luX3NjUk5BIDwtIFJ1blBDQSh0cmF2aXNfTk1fc2tpbl9zY1JOQSwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IHRyYXZpc19OTV9za2luX3NjUk5BKSkKdHJhdmlzX05NX3NraW5fc2NSTkEgPC0gRmluZE5laWdoYm9ycyh0cmF2aXNfTk1fc2tpbl9zY1JOQSwgZGltcyA9IDE6NDApCnRyYXZpc19OTV9za2luX3NjUk5BIDwtIEZpbmRDbHVzdGVycyh0cmF2aXNfTk1fc2tpbl9zY1JOQSwgcmVzb2x1dGlvbiA9IDEpCnRyYXZpc19OTV9za2luX3NjUk5BIDwtIFJ1blVNQVAodHJhdmlzX05NX3NraW5fc2NSTkEsIGRpbXMgPSAxOjQwKQpgYGAKIyMgTm9ybWFsIHNraW4gLSBzY1JOQSBkYXRhIGZyb20gVHJhdmlzIHBhcGVyIApgYGB7cn0KSWRlbnRzKHRyYXZpc19OTV9za2luX3NjUk5BKSA8LSAiU3BlY2lmaWNfQ2VsbFR5cGUiCkRpbVBsb3QodHJhdmlzX05NX3NraW5fc2NSTkEscHQuc2l6ZSA9IDIuNSxsYWJlbCA9IFRSVUUpCgpJZGVudHModHJhdmlzX05NX3NraW5fc2NSTkEpIDwtICJDZWxsVHlwZSIKRGltUGxvdCh0cmF2aXNfTk1fc2tpbl9zY1JOQSxwdC5zaXplID0gMi41KQpgYGAKCmBgYHtyfQpzYXZlKHRyYXZpc19OTV9za2luX3NjUk5BLGZpbGUgPSAiLi4vLi4vVFJBVklTX3NjUk5BX0RBVEEvdHJhdmlzX05NX3NraW5fc2NSTkEuUkRTIikKYGBgCgpgYGB7cn0Kc2luZ2xlX2NlbGwubWFya2VycyA8LSBGaW5kQWxsTWFya2Vycyh0cmF2aXNfTk1fc2tpbl9zY1JOQSxhc3NheSA9ICJSTkEiLGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCmBgYAoKYGBge3J9CmZpbHRlcmVkX3NpbmdsZV9jZWxsLm1hcmtlcnMgPC0gc2luZ2xlX2NlbGwubWFya2VycyAlPiUgZmlsdGVyKHBfdmFsX2Fkajw9MC4wNSkgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0zMDAsd3QgPSBhdmdfbG9nMkZDKSAlPiUgZmlsdGVyKGF2Z19sb2cyRkM+MC4yNSkKZmlsdGVyZWRfc3BhdGlhbF9tYXJrZXJzIDwtIG5ldy5za2luLmNvbWJpbmVkLm1hcmtlcnMgJT4lIGZpbHRlcihwX3ZhbF9hZGo8PTAuMDUpICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9MzAwLHd0ID0gYXZnX2xvZzJGQykgJT4lIGZpbHRlcihhdmdfbG9nMkZDPjAuMjUpCmBgYAoKIyBGaWd1cmUgLSAyQgpgYGB7cn0KIyNJTlRFUlNFQ1QgR0VORVMgQkVUV0VFTiBzY1JOQSBhbmQgU3BhdGlhbCBkYXRhCnN0LmdlbmVzIDwtIHVuaXF1ZShyb3duYW1lcyhuZXcuc2tpbi5jb21iaW5lZEBhc3NheXMkU3BhdGlhbEBjb3VudHMpKQpzYy5nZW5lcyA8LSB1bmlxdWUocm93bmFtZXModHJhdmlzX05NX3NraW5fc2NSTkFAYXNzYXlzJFJOQUBjb3VudHMpKQphbGwuZ2VuZXMuc2NybmFfYW5kX3NwdCA8LSB1bmlxdWUoaW50ZXJzZWN0KHNjLmdlbmVzLHN0LmdlbmVzKSkKYGBgCmBgYHtyfQpNSUFfcmVzdWx0cyA8LSBNSUEodG90YWxfZ2VuZXMgPSBsZW5ndGgoYWxsLmdlbmVzLnNjcm5hX2FuZF9zcHQpLHNpbmdsZV9jZWxsLm1hcmtlcnMgPSBmaWx0ZXJlZF9zaW5nbGVfY2VsbC5tYXJrZXJzLHNwYXRpYWwubWFya2VycyA9IGZpbHRlcmVkX3NwYXRpYWxfbWFya2VycykKCkUuZGF0YSA8LSBNSUFfcmVzdWx0cyAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJjbHVzdGVyIikKRS5kYXRhIDwtIEUuZGF0YVssb3JkZXIoY29sbmFtZXMoRS5kYXRhKSldCnBoZWF0bWFwKEUuZGF0YSxjbHVzdGVyX2NvbHMgPSBGQUxTRSxjbHVzdGVyX3Jvd3MgPSBGQUxTRSxmb250c2l6ZT0xNSxjb2xvciA9IGNvbC5wYWwpCmBgYAoKYGBge3J9CmltbXVuZV9vbmx5LkUuZGF0YSA8LSBFLmRhdGFbLGMoIlQgY2VsbC0xIiwiVCBjZWxsLTIiLCJUIGNlbGwtMyIsIk15ZWxvaWQtMSIsIkxhbmdlcmhhbnMiLCJNYXN0LTEiLCJNYXN0LTIiKV0KcGRmKGZpbGUgPSAiTUlBX3JlZ2lvbnNfSU1NVU5FX0NFTExTLnBkZiIsd2lkdGggPSAxMCxoZWlnaHQgPSA0KQpwaGVhdG1hcChpbW11bmVfb25seS5FLmRhdGEsY2x1c3Rlcl9jb2xzID0gRkFMU0UsY2x1c3Rlcl9yb3dzID0gRkFMU0UsZm9udHNpemU9MTUsY29sb3IgPSBjb2wucGFsKQpkZXYub2ZmKCkKYGBgCmBgYHtyfQpzdHJ1Y3R1cmVfb25seS5FX2RhdGEgPC0gRS5kYXRhWyxjKCJGaWJyb2JsYXN0LTEiLCJGaWJyb2JsYXN0LTIiLCJGaWJyb2JsYXN0LTQiLCJGaWJyb2JsYXN0LTUiLCJIYWlyRm9sbGljbGUiLCJLZXJhdGlub2N5dGUtMiIsIktlcmF0aW5vY3l0ZS0zIiwiS2VyYXRpbm9jeXRlLTUiLCJLZXJhdGlub2N5dGUtNiIsIktlcmF0aW5vY3l0ZS04IiwiU2Vib2N5dGUiLCJWZW51bGUtMSIsIlZlbnVsZS0yIiwiVmVudWxlLTMiLCJWZW51bGUtNCIsIlZTTUMtMSIpXQpwZGYoZmlsZSA9ICJNSUFfcmVnaW9uc19TVFJVQ1RVUkFMX0NFTExTLnBkZiIsd2lkdGggPSAxMCxoZWlnaHQgPSA0KQpwaGVhdG1hcChzdHJ1Y3R1cmVfb25seS5FX2RhdGEsY2x1c3Rlcl9jb2xzID0gRkFMU0UsY2x1c3Rlcl9yb3dzID0gRkFMU0UsZm9udHNpemU9MTUsY29sb3IgPSBjb2wucGFsKQpkZXYub2ZmKCkKYGBgCgojIyBOT1cgQ0FMQ1VMQVRJTkcgRU5SSUNITUVOVCBVU0lORyBORVcgREFUQVNFVCAoVHJhdmlzIGV0IGFsKQojIFNldXJhdCBiYXNlZCBjZWxsIHR5cGUgZW5yaWNobWVudApgYGB7cixldmFsPUZBTFNFfQojIFJVTiBUSElTIE9OIEJJRyBQVVJQTEUgCnNraW5fcmVmZXJlbmNlLjIgPC0gU0NUcmFuc2Zvcm0odHJhdmlzX3RyYXZpc19OTV9za2luX3NjUk5BLCBuY2VsbHMgPSAzMDAwLCB2ZXJib3NlID0gRkFMU0UpICU+JSBSdW5QQ0EodmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICBSdW5VTUFQKGRpbXMgPSAxOjQwKQphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gc2tpbl9yZWZlcmVuY2UuMiwgcXVlcnkgPSBuZXcuc2tpbi5jb21iaW5lZCwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIikKcHJlZGljdGlvbnMuYXNzYXkgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBza2luX3JlZmVyZW5jZS4yJFNwZWNpZmljX0NlbGxUeXBlLCBwcmVkaWN0aW9uLmFzc2F5ID0gVFJVRSwgCiAgICB3ZWlnaHQucmVkdWN0aW9uID0gbmV3LnNraW4uY29tYmluZWRbWyJwY2EiXV0sZGltcyA9IDE6NDApCm5ldy5za2luLmNvbWJpbmVkW1sicHJlZGljdGlvbnNfdHJhdmlzX2RhdGEiXV0gPC0gcHJlZGljdGlvbnMuYXNzYXkKYGBgCgojIyBDRUxMIFRZUEVTIEZPUiBGSUdVUkUgMSAtIFRyYXZpcyBldCBhbC4gc2luZ2xlIGNlbGwgZGF0YXNldCAoT25seSB1c2luZyB0aGUgaGVhbHRoeSBzdWJzZXQgb2Ygc2NSTkEgZGF0YSkKYGBge3J9CkNlbGxfdHlwZXMgPC0gYygiRmlicm9ibGFzdC0xIiwiSGFpckZvbGxpY2xlIiwiS2VyYXRpbm9jeXRlLTUiLCJLZXJhdGlub2N5dGUtMyIsIlNlYm9jeXRlIiwiVlNNQy0xIiwiTWVsYW5vY3l0ZSIpCkRlZmF1bHRBc3NheShuZXcuc2tpbi5jb21iaW5lZCkgPC0gInByZWRpY3Rpb25zX3RyYXZpc19kYXRhIgpmb3IgKHggaW4gQ2VsbF90eXBlcyl7CiAgcGRmKGZpbGUgPSBwYXN0ZSgiSEVBTFRIWV9GRU1BTEVfMV9SMl9DRUxMX1RZUEVfIix4LCIucGRmIiksd2lkdGggPSAxMCxoZWlnaHQgPSAxNSkKICBwcmludChTcGF0aWFsRmVhdHVyZVBsb3QobmV3LnNraW4uY29tYmluZWQsIGZlYXR1cmVzID0gYyh4KSwgcHQuc2l6ZS5mYWN0b3IgPSAyLjUsIG5jb2wgPSAyLCBjcm9wID0gVFJVRSxpbWFnZXMgPSAiSGVhbHRoeUZlbWFsZS4xLlMyIikgKyBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Y29scyxsaW1pdHMgPSBjKDAsMSkpKSAKICBkZXYub2ZmKCkKfQpgYGAKCiMgUEVSQ0VOVEFHRSBQTE9UIEZPUiBESUZGRVJFTlQgU1BBVElBTCBSRUdJT05TCiMgQ2FsY3VsYXRlZCBvbiBhIHBlciBzYW1wbGUgYmFzaXMKYGBge3J9ClJlZ2lvbnMuZGYgPC0gdGFibGUobmV3LnNraW4uY29tYmluZWRAbWV0YS5kYXRhJFNwYXRpYWwucmVnaW9ucyxuZXcuc2tpbi5jb21iaW5lZEBtZXRhLmRhdGEkb3JpZy5pZGVudCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnJlbmFtZShTcGF0aWFsX1JlZ2lvbj1WYXIxLFNhbXBsZT1WYXIyKSAKCmJsYWNrLmJvbGQuMTYudGV4dCA8LSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMTQsYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpCmJya3MgPC0gYygwLCAwLjI1LCAwLjUsIDAuNzUsIDEpCgpwZGYoZmlsZT0iUEVSQ0VOVEFHRV9DT01QT1NUSU9OX1BMT1RfSEVBTFRIWV9TQU1QTEVTLnBkZiIsaGVpZ2h0ID0gMTQsd2lkdGggPSA4KQpnZ3Bsb3QoUmVnaW9ucy5kZixhZXMoeD1TYW1wbGUseT1GcmVxLGZpbGw9U3BhdGlhbF9SZWdpb24pKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbj0iZmlsbCIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID1jdXN0b21fY29sb3JzKSAgKyBnZ3Bsb3QyOjp0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLApwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54ID1ibGFjay5ib2xkLjE2LnRleHQpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGJya3MsIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudChicmtzKSkgKyB5bGFiKCIlIENvbXBvc2l0aW9uIG9mIFNhbXBsZSBieSBTcGF0aWFsIFJlZ2lvbiAvIENsdXN0ZXJzIikKZGV2Lm9mZigpCmBgYAoKIyBDZWxsIGNvdW50cyBmb3IgdHJhdmlzIGhlYWx0aHkgc3Vic2V0IGRhdGEKYGBge3J9CmNlbGwuY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUodHJhdmlzX05NX3NraW5fc2NSTkFAbWV0YS5kYXRhJFNwZWNpZmljX0NlbGxUeXBlKSkKd3JpdGUuY3N2KGNlbGwuY291bnRzLGZpbGU9Ii4uLy4uL1RSQVZJU19zY1JOQV9EQVRBL0NFTExfQ09VTlRTX1RSQVZJU19IRUFMVEhZX1NLSU5fREFUQS5jc3YiKQpgYGAKCiMgRmlsdGVyZWQgb3V0IGNlbGwgdHlwZXMgd2l0aCBsZXNzIHRoYW4gNTAgY2VsbHMKYGBge3J9CmZpbHRlcmVkX2NlbGwuY291bnRzIDwtIGNlbGwuY291bnRzICU+JSBmaWx0ZXIoRnJlcT41MCkgCklkZW50cyh0cmF2aXNfTk1fc2tpbl9zY1JOQSkgPC0gIlNwZWNpZmljX0NlbGxUeXBlIgp0cmF2aXNfaGVhbHRoeV9kYXRhLnN1YnNldCA8LSBzdWJzZXQoeCA9IHRyYXZpc19OTV9za2luX3NjUk5BLCBpZGVudHMgPSBjKGZpbHRlcmVkX2NlbGwuY291bnRzJFZhcjEpKQoKRGltUGxvdCh0cmF2aXNfaGVhbHRoeV9kYXRhLnN1YnNldCxwdC5zaXplID0gMi41KQpgYGAKIyBQbG90dGluZyBmaW5hbCB0cmF2aXMgaGVhbHRoeSBkYXRhIFVNQVAKYGBge3J9CnBkZih3aWR0aCA9IDEyLGhlaWdodD04LGZpbGUgPSAiVU1BUF9UUkFWSVNfREFUQV9IRUFMVEhZX1NBTVBMRVNfT05MWS5wZGYiKQpEaW1QbG90KHRyYXZpc19oZWFsdGh5X2RhdGEuc3Vic2V0LHB0LnNpemUgPSAzLjUpCmRldi5vZmYoKQpgYGAKCiMjIFBBVEhXQVkgQU5BTFlTSVMgRk9SIFNQQVRJQUwgSEVBTFRIWSBEQVRBIC0gUEVSIENMVVNURVIgQkFTSVMKYGBge3J9CmZvcihpIGluIHNlcSgwLDExKSl7CiAgY2x1c3RlciA8LSBuZXcuc2tpbi5jb21iaW5lZC5tYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3Rlcj09aSkKICBHT19QQVRIV0FZU19FTlJJQ0goY2x1c3RlcixPTlQ9IkJQIixPVVRQVVQgPSBpKQogIEdPX1BBVEhXQVlTX0VOUklDSChjbHVzdGVyLE9OVD0iQ0MiLE9VVFBVVCA9IGkpCiAgR09fUEFUSFdBWVNfRU5SSUNIKGNsdXN0ZXIsT05UPSJNRiIsT1VUUFVUID0gaSkKICBLRUdHX1BBVEhXQVlTKGNsdXN0ZXIsT1VUUFVUID0gaSkKfQpgYGAKCiMgTnVtYmVyIG9mIGdlbmVzIHVzZWQgaW4gTUlBIC0gKE5lZWRlZCBmb3IgVmVubiBkaWFncmFtKQpgYGB7cixldmFsPUZBTFNFfQoKY2x1c3Rlci41IDwtIGZpbHRlcmVkX3NwYXRpYWxfbWFya2VycyAlPiUgZmlsdGVyKGNsdXN0ZXI9PTUpCk15ZWxvaWQuMSA8LSBmaWx0ZXJlZF9zaW5nbGVfY2VsbC5tYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3Rlcj09Ik15ZWxvaWQtMSIpCgpsZW5ndGgoaW50ZXJzZWN0KGNsdXN0ZXIuNSRnZW5lLE15ZWxvaWQuMSRnZW5lKSkKCmNsdXN0ZXIuNiA8LSBmaWx0ZXJlZF9zcGF0aWFsX21hcmtlcnMgJT4lIGZpbHRlcihjbHVzdGVyPT02KQpLZXJhdGlub2N5dGUuNSA8LSBmaWx0ZXJlZF9zaW5nbGVfY2VsbC5tYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3Rlcj09IktlcmF0aW5vY3l0ZS01IikKCmxlbmd0aChpbnRlcnNlY3QoY2x1c3Rlci42JGdlbmUsS2VyYXRpbm9jeXRlLjUkZ2VuZSkpCmBgYAoKCgojIyBMT0FEIERBVEEgRlJPTSBIQU5OSUZBIFBBUEVSCmBgYHtyfQpsb2FkKCIuLi8uLi9zY1JOQV9EQVRBL0hFQUxUSFlfU0NfUk5BX1BST0NFU1NFRC5SRGF0YSIpCmBgYAoKIyBVTUFQIHBsb3QgZm9yIEhhbm5pZmEgaGVhbHRoeSBza2luIGRhdGEKYGBge3J9CkRpbVBsb3QoaGVhbHRoeV9za2luLnNjX2RhdGEscmFzdGVyID0gRkFMU0UpCgpwZGYoZmlsZSA9ICJVTUFQX09OTFlfSEVBTFRIWV9TQU1QTEVTXyhIQU5OSUZBX1BBUEVSKS5wZGYiLHdpZHRoID0gMTYsaGVpZ2h0PTgpCnByaW50KERpbVBsb3QoaGVhbHRoeV9za2luLnNjX2RhdGFfc3Vic2V0LHB0LnNpemUgPSAxLjIsc2h1ZmZsZSA9IFRSVUUscmFzdGVyPUZBTFNFKSkKZGV2Lm9mZigpCmBgYAojIElkZW50aWZ5IG1hcmtlciBnZW5lcyBmb3IgdGhlIHByZS1hc3NpZ25lZCBjbHVzdGVyaW5nIHJlc3VsdHMgd2l0aCBjZWxsIHR5cGUgbGFiZWxzCmBgYHtyfQpJZGVudHMoaGVhbHRoeV9za2luLnNjX2RhdGEpIDwtICJmaW5hbF9jbHVzdGVyaW5nIgpobmZfc2tpbl9zY1JOQS5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKGhlYWx0aHlfc2tpbi5zY19kYXRhLGFzc2F5ID0gIlJOQSIsbG9nZmMudGhyZXNob2xkID0gMC4yNSxtYXguY2VsbHMucGVyLmlkZW50PTQwMCxvbmx5LnBvcyA9IFRSVUUpCmBgYAoKIyBMb2FkIE1BUktFUiBHRU5FUyBmcm9tIHRoZSBzYXZlZCBmaWxlIGZvciBsYXRlciB1c2UKYGBge3J9CmhuZl9za2luX3NjUk5BLm1hcmtlcnMgPC0gcmVhZC5jc3YoIi4uLy4uL3NjUk5BX0RBVEEvSEFOTklGQV9NQVJLRVJTLmNzdiIpICU+JSBmaWx0ZXIocF92YWxfYWRqPD0wLjA1KSAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPTMwMCx3dCA9IGF2Z19sb2cyRkMpICU+JSBmaWx0ZXIoYXZnX2xvZzJGQz4wLjI1KQpgYGAKCiNTQy1EQVRBIC0gY2VsbCBjb3VudHMKYGBge3J9CmhuZl9kYXRhX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGhlYWx0aHlfc2tpbi5zY19kYXRhQG1ldGEuZGF0YSRmaW5hbF9jbHVzdGVyaW5nKSkKd3JpdGUuY3N2KGhuZl9kYXRhX2NvdW50cyxmaWxlPSJIRUFMVEhZX1NBTVBMRVNfSEFOTklGQV9EQVRBX0NPVU5UUy5jc3YiKQpgYGAKCiMgSW50ZXJzZWN0aW5nIGdlbmVzIGJldHdlZW4gU1QgYW5kIHNjUk5BIGRhdGEuCmBgYHtyfQojI0lOVEVSU0VDVCBHRU5FUyBCRVRXRUVOIHNjUk5BIGFuZCBTcGF0aWFsIGRhdGEKc3QuZ2VuZXMgPC0gdW5pcXVlKHJvd25hbWVzKG5ldy5za2luLmNvbWJpbmVkQGFzc2F5cyRTcGF0aWFsQGNvdW50cykpCnNjLmdlbmVzIDwtIHVuaXF1ZShyb3duYW1lcyhoZWFsdGh5X3NraW4uc2NfZGF0YUBhc3NheXMkUk5BQGNvdW50cykpCmFsbC5nZW5lcy5zY3JuYV9hbmRfc3B0IDwtIHVuaXF1ZShpbnRlcnNlY3Qoc2MuZ2VuZXMsc3QuZ2VuZXMpKQpgYGAKCiMjIE1JQSBGT1IgSEFOTklGQSBQQVBFUiAtIGhlYWx0aHkgc2FtcGxlcyBkYXRhIG9ubHkKYGBge3J9Ck1JQV9yZXN1bHRzX1BBUlRfMiA8LSBNSUEodG90YWxfZ2VuZXMgPSBsZW5ndGgoYWxsLmdlbmVzLnNjcm5hX2FuZF9zcHQpLHNpbmdsZV9jZWxsLm1hcmtlcnMgPSBobmZfc2tpbl9zY1JOQS5tYXJrZXJzLHNwYXRpYWwubWFya2VycyA9IGZpbHRlcmVkX3NwYXRpYWxfbWFya2VycykKCkUuZGF0YV9QQVJUXzIgPC0gTUlBX3Jlc3VsdHNfUEFSVF8yICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoImNsdXN0ZXIiKQpFLmRhdGFfUEFSVF8yIDwtIEUuZGF0YV9QQVJUXzJbLG9yZGVyKGNvbG5hbWVzKEUuZGF0YV9QQVJUXzIpKV0KaXMubmEoRS5kYXRhX1BBUlRfMikgPC0gZG8uY2FsbChjYmluZCxsYXBwbHkoRS5kYXRhX1BBUlRfMiwgaXMuaW5maW5pdGUpKQpwaGVhdG1hcChFLmRhdGFfUEFSVF8yLGNsdXN0ZXJfY29scyA9IEZBTFNFLGNsdXN0ZXJfcm93cyA9IEZBTFNFLGZvbnRzaXplPTE1LGNvbG9yID0gY29sLnBhbCkKYGBgCgojIEZvciBJbW11bmUgcG9wdWxhdGlvbnMKYGBge3J9CiMjIElNTVVORSBDRUxMUwppbW11bmVfb25seS5FLmRhdGFfUEFSVF8yIDwtIEUuZGF0YV9QQVJUXzJbLGMoIkRDMSIsIkRDMiIsIk1hY3JvXzEiLCJNYWNyb18yIiwibW9EQ18xIiwibW9EQ18yIiwibW9EQ18zIiwiTWlnREMiLCJNb25vIiwiSW5mX21vbm8iLCJJTEMxX05LIiwiSUxDMV8zIiwiSUxDMiIsIlRjIiwiVGgiLCJUcmVnIiwiTWFzdF9jZWxsIiwiUGxhc21hIiwiTksiKV0KcGRmKGZpbGUgPSAiTUlBX3JlZ2lvbnNfKEhBTk5JRkFfUEFQRVIpX0lNTVVORV9DRUxMUy5wZGYiLHdpZHRoID0gMTAsaGVpZ2h0ID0gNSkKcHJpbnQocGhlYXRtYXAoaW1tdW5lX29ubHkuRS5kYXRhX1BBUlRfMixjbHVzdGVyX2NvbHMgPSBGQUxTRSxjbHVzdGVyX3Jvd3MgPSBGQUxTRSxmb250c2l6ZT0xNSxjb2xvciA9IGNvbC5wYWwpKQpkZXYub2ZmKCkKYGBgCgojIEZvciBub24taW1tdW5lIHBvcHVsYXRpb25zCmBgYHtyfQpub25faW1tdW5lX29ubHkuRS5kYXRhX1BBUlRfMiA8LSBFLmRhdGFfUEFSVF8yICU+JSBkcGx5cjo6c2VsZWN0KC1jKCJEQzEiLCJEQzIiLCJNYWNyb18xIiwiTWFjcm9fMiIsIm1vRENfMSIsIm1vRENfMiIsIm1vRENfMyIsIk1pZ0RDIiwiTW9ubyIsIkluZl9tb25vIiwiSUxDMV9OSyIsIklMQzFfMyIsIklMQzIiLCJUYyIsIlRoIiwiVHJlZyIsIk1hc3RfY2VsbCIsIlBsYXNtYSIsIk5LIiwibmFuIikpCnBkZihmaWxlID0gIk1JQV9yZWdpb25zXyhIQU5OSUZBX1BBUEVSKV9OT05fSU1NVU5FX0NFTExTLnBkZiIsd2lkdGggPSAxMCxoZWlnaHQgPSA1KQpwcmludChwaGVhdG1hcChub25faW1tdW5lX29ubHkuRS5kYXRhX1BBUlRfMixjbHVzdGVyX2NvbHMgPSBGQUxTRSxjbHVzdGVyX3Jvd3MgPSBGQUxTRSxmb250c2l6ZT0xNSxjb2xvciA9IGNvbC5wYWwpKQpkZXYub2ZmKCkKYGBgCgoKCmBgYHtyfQojVklPTElOIFBMT1QgRk9SIFVNSXMgYW5kIFNFVVJBVCBDTFVTVEVSUwpwZGYoZmlsZSA9ICJWSU9MSU5fUExPVF9VTUlzX2FuZF9DTFVTVEVSU19IRUFMVEhZX1NBTVBMRVMucGRmIix3aWR0aCA9IDE2LGhlaWdodD0xMikKcHJpbnQoVmxuUGxvdChuZXcuc2tpbi5jb21iaW5lZCxncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLGZlYXR1cmVzID0gIm5Db3VudF9TcGF0aWFsIixjb2xzID0gY3VzdG9tX2NvbG9ycykpCmRldi5vZmYoKQoKIyBMT0cgVFJBTlNGT1JNRUQgVU1JIENPVU5UUwpwZGYoZmlsZSA9ICJWSU9MSU5fUExPVF9VTUlzX2FuZF9DTFVTVEVSU19IRUFMVEhZX1NBTVBMRVMoTE9HX1RSQU5TRk9STUVEKS5wZGYiLHdpZHRoID0gMTYsaGVpZ2h0PTEyKQpwcmludChWbG5QbG90KG5ldy5za2luLmNvbWJpbmVkLGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsZmVhdHVyZXMgPSAibkNvdW50X1NwYXRpYWwiLGNvbHMgPSBjdXN0b21fY29sb3JzLGxvZyA9IFRSVUUpKQpkZXYub2ZmKCkKYGBgCgpgYGB7cn0KIyBTUE9UIEZSRVFVRU5DWSBUQUJMRSAtIEJZIFNQQVRJQUwgUkVHSU9OCnNwYXRpYWwuZnJlcSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKG5ldy5za2luLmNvbWJpbmVkQG1ldGEuZGF0YSRTcGF0aWFsLnJlZ2lvbnMpKQp3cml0ZS5jc3Yoc3BhdGlhbC5mcmVxLGZpbGU9IlNQQVRJQUxfUkVHSU9OU19DTFVTVEVSU19TUE9UX0NPVU5UUy5jc3YiKQpgYGAKCiMjIFFDIEZJR1VSRVMgLSBSZXBsb3R0aW5nCiMgU3VwcGxlbWVudGFyeSBmaWd1cmUgLSAyCmBgYHtyfQojIEhFQUxUSFkgRkVNQUxFIFNLSU4gMgojUkVNT1ZFIFNQT1RTCkhFQUxUSFkuRmVtYWxlMS5zMyA8LSBMb2FkMTBYX1NwYXRpYWwoZGF0YS5kaXIgPSIuLi8uLi9TRVZFTlRIIFJVTi9TVC1IRi0xLyIsc2xpY2U9IkhlYWx0aHlGZW1hbGUtMS1TMyIpCgojIyBIRUFMVEhZIEZFTUFMRQpIRUFMVEhZLkZlbWFsZTIuczEgPC0gTG9hZDEwWF9TcGF0aWFsKGRhdGEuZGlyID0iLi4vLi4vU0VWRU5USCBSVU4vU1QtSEYtMkUvIixzbGljZT0iSGVhbHRoeUZlbWFsZS0yLVMxIikKSEVBTFRIWS5GZW1hbGUyLnMyIDwtIExvYWQxMFhfU3BhdGlhbChkYXRhLmRpciA9Ii4uLy4uL1NFVkVOVEggUlVOL1NULUhGLTJGLyIsc2xpY2U9IkhlYWx0aHlGZW1hbGUtMi1TMiIpCgojSEVBTEFUSFkgTUFMRQpIRUFMVEhZLk1hbGUuczIgPC0gTG9hZDEwWF9TcGF0aWFsKGRhdGEuZGlyID0iLi4vLi4vU0VWRU5USCBSVU4vU1QtSE0tMS8iLHNsaWNlPSJIZWFsdGh5TWFsZS0xLVMyIikKYGBgCmBgYHtyfQpyZW1vdmUuc3BvdHMgPC0gcmVhZC5jc3YoZmlsZT0iLi4vLi4vQ0xPVVBFX0ZJTEVTL1NFVkVOVEhfUlVOL0hGLTEtU1AvcmVtb3ZlLmNzdiIpCnN1YnNldF9zcG90cyA8LSBDZWxscyhIRUFMVEhZLkZlbWFsZTEuczMpW3doaWNoKCghKHJvd25hbWVzKEhFQUxUSFkuRmVtYWxlMS5zM0BtZXRhLmRhdGEpICVpbiUgcmVtb3ZlLnNwb3RzJEJhcmNvZGUpKSldCkhFQUxUSFkuRmVtYWxlMS5zMy5jbGVhbiA8LSBzdWJzZXQoSEVBTFRIWS5GZW1hbGUxLnMzLGNlbGxzPXN1YnNldF9zcG90cykKCnBkZih3aWR0aCA9IDgsaGVpZ2h0PTEwLGZpbGUgPSAiSFYyX1NQX1NQQVRJQUxfUExPVChVTkZJTFRFUkVEKS5wZGYiKQpwcmludChTcGF0aWFsRGltUGxvdChIRUFMVEhZLkZlbWFsZTEuczMuY2xlYW4scHQuc2l6ZS5mYWN0b3IgPSAyLGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKSkKZGV2Lm9mZigpCgpwZGYod2lkdGggPSA4LGhlaWdodD0xMCxmaWxlID0gIkhWMl9TUF9TUEFUSUFMX1BMT1QoRklMVEVSRUQpLnBkZiIpCnByaW50KFNwYXRpYWxEaW1QbG90KG5ldy5za2luLmNvbWJpbmVkLGltYWdlcyA9ICJIZWFsdGh5RmVtYWxlLjEuUzMiLHB0LnNpemUuZmFjdG9yID0gMixncm91cC5ieSA9ICJvcmlnLmlkZW50IikpCmRldi5vZmYoKQpgYGAKCmBgYHtyfQpyZW1vdmUuc3BvdHMgPC0gcmVhZC5jc3YoZmlsZT0iLi4vLi4vQ0xPVVBFX0ZJTEVTL1NFVkVOVEhfUlVOL0hGLTItU0UvUmVtb3ZlLmNzdiIpCnN1YnNldF9zcG90cyA8LSBDZWxscyhIRUFMVEhZLkZlbWFsZTIuczEpW3doaWNoKCghKHJvd25hbWVzKEhFQUxUSFkuRmVtYWxlMi5zMUBtZXRhLmRhdGEpICVpbiUgcmVtb3ZlLnNwb3RzJEJhcmNvZGUpKSldCkhFQUxUSFkuRmVtYWxlMi5zMS5jbGVhbiA8LSBzdWJzZXQoSEVBTFRIWS5GZW1hbGUyLnMxLGNlbGxzPXN1YnNldF9zcG90cykKCnBkZih3aWR0aCA9IDgsaGVpZ2h0PTEwLGZpbGUgPSAiSFYzX1NFX1NQQVRJQUxfUExPVChVTkZJTFRFUkVEKS5wZGYiKQpwcmludChTcGF0aWFsRGltUGxvdChIRUFMVEhZLkZlbWFsZTIuczEuY2xlYW4scHQuc2l6ZS5mYWN0b3IgPSAyLGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKSkKZGV2Lm9mZigpCgpwZGYod2lkdGggPSA4LGhlaWdodD0xMCxmaWxlID0gIkhWM19TRV9TUEFUSUFMX1BMT1QoRklMVEVSRUQpLnBkZiIpCnByaW50KFNwYXRpYWxEaW1QbG90KG5ldy5za2luLmNvbWJpbmVkLGltYWdlcyA9ICJIZWFsdGh5RmVtYWxlLjIuUzEiLHB0LnNpemUuZmFjdG9yID0gMixncm91cC5ieSA9ICJvcmlnLmlkZW50IikpCmRldi5vZmYoKQpgYGAKYGBge3J9CnJlbW92ZS5zcG90cyA8LSByZWFkLmNzdihmaWxlPSIuLi8uLi9DTE9VUEVfRklMRVMvU0VWRU5USF9SVU4vSEYtMi1TUC9SZW1vdmUuY3N2IikKc3Vic2V0X3Nwb3RzIDwtIENlbGxzKEhFQUxUSFkuRmVtYWxlMi5zMilbd2hpY2goKCEocm93bmFtZXMoSEVBTFRIWS5GZW1hbGUyLnMyQG1ldGEuZGF0YSkgJWluJSByZW1vdmUuc3BvdHMkQmFyY29kZSkpKV0KSEVBTFRIWS5GZW1hbGUyLnMyLmNsZWFuIDwtIHN1YnNldChIRUFMVEhZLkZlbWFsZTIuczIsY2VsbHM9c3Vic2V0X3Nwb3RzKQoKcGRmKHdpZHRoID0gOCxoZWlnaHQ9MTAsZmlsZSA9ICJIVjNfU1BfU1BBVElBTF9QTE9UKFVORklMVEVSRUQpLnBkZiIpCnByaW50KFNwYXRpYWxEaW1QbG90KEhFQUxUSFkuRmVtYWxlMi5zMi5jbGVhbixwdC5zaXplLmZhY3RvciA9IDIsZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpKQpkZXYub2ZmKCkKCnBkZih3aWR0aCA9IDgsaGVpZ2h0PTEwLGZpbGUgPSAiSFYzX1NQX1NQQVRJQUxfUExPVChGSUxURVJFRCkucGRmIikKcHJpbnQoU3BhdGlhbERpbVBsb3QobmV3LnNraW4uY29tYmluZWQsaW1hZ2VzID0gIkhlYWx0aHlGZW1hbGUuMi5TMiIscHQuc2l6ZS5mYWN0b3IgPSAyLGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKSkKZGV2Lm9mZigpCmBgYAoKYGBge3J9CnJlbW92ZS5zcG90cyA8LSByZWFkLmNzdihmaWxlPSIuLi8uLi9DTE9VUEVfRklMRVMvU0VWRU5USF9SVU4vSE0tU1AtMi9yZW1vdmUuY3N2IikKc3Vic2V0X3Nwb3RzIDwtIENlbGxzKEhFQUxUSFkuTWFsZS5zMilbd2hpY2goKCEocm93bmFtZXMoSEVBTFRIWS5NYWxlLnMyQG1ldGEuZGF0YSkgJWluJSByZW1vdmUuc3BvdHMkQmFyY29kZSkpKV0KSEVBTFRIWS5NYWxlLnMyLmNsZWFuIDwtIHN1YnNldChIRUFMVEhZLk1hbGUuczIsY2VsbHM9c3Vic2V0X3Nwb3RzKQoKcGRmKHdpZHRoID0gOCxoZWlnaHQ9MTAsZmlsZSA9ICJIVjFfU1BfUjJfU1BBVElBTF9QTE9UKFVORklMVEVSRUQpLnBkZiIpCnByaW50KFNwYXRpYWxEaW1QbG90KEhFQUxUSFkuTWFsZS5zMi5jbGVhbixwdC5zaXplLmZhY3RvciA9IDIuMixncm91cC5ieSA9ICJvcmlnLmlkZW50IikpCmRldi5vZmYoKQoKcGRmKHdpZHRoID0gOCxoZWlnaHQ9MTAsZmlsZSA9ICJIVjFfU1BfUjJfU1BBVElBTF9QTE9UKEZJTFRFUkVEKS5wZGYiKQpwcmludChTcGF0aWFsRGltUGxvdChuZXcuc2tpbi5jb21iaW5lZCxpbWFnZXMgPSAiSGVhbHRoeU1hbGUuMS5TMiIscHQuc2l6ZS5mYWN0b3IgPSAyLjIsZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpKQpkZXYub2ZmKCkKCmBgYAojIyMgSW1wb3J0IHRoZSBzcG90cyB0byBiZSByZW1vdmVkIGZyb20gbG91cGUgYnJvd3Nlci4KYGBge3J9CnJlbW92ZS5zcG90cyA8LSByZWFkLmNzdihmaWxlPSIuLi8uLi9GSUZUSF9SVU4vU0FNUExFIEQxL1JFTU9WRS5jc3YiKQpzdWJzZXRfc3BvdHMgPC0gQ2VsbHMoSEVBTFRIWS5GZW1hbGUxLnMyKVt3aGljaCgoIShyb3duYW1lcyhIRUFMVEhZLkZlbWFsZTEuczJAbWV0YS5kYXRhKSAlaW4lIHJlbW92ZS5zcG90cyRCYXJjb2RlKSkpXQpIRUFMVEhZLkZlbWFsZTEuczIuY2xlYW4gPC0gc3Vic2V0KEhFQUxUSFkuRmVtYWxlMS5zMixjZWxscz1zdWJzZXRfc3BvdHMpCmBgYApgYGB7cn0KU3BhdGlhbERpbVBsb3QoSEVBTFRIWS5GZW1hbGUuczIuY2xlYW4pClNwYXRpYWxEaW1QbG90KEhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbikKCnBkZih3aWR0aCA9IDgsaGVpZ2h0PTEwLGZpbGUgPSAiSFYyX1NQX1IyX1NQQVRJQUxfUExPVChVTkZJTFRFUkVEKS5wZGYiKQpwcmludChTcGF0aWFsRGltUGxvdChIRUFMVEhZLkZlbWFsZTEuczIuY2xlYW4scHQuc2l6ZS5mYWN0b3IgPSAyLjIsZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpKQpkZXYub2ZmKCkKCnBkZih3aWR0aCA9IDgsaGVpZ2h0PTEwLGZpbGUgPSAiSFYyX1NQX1IyX1NQQVRJQUxfUExPVChGSUxURVJFRCkucGRmIikKcHJpbnQoU3BhdGlhbERpbVBsb3QobmV3LnNraW4uY29tYmluZWQsaW1hZ2VzID0gIkhlYWx0aHlGZW1hbGUuMS5TMiIscHQuc2l6ZS5mYWN0b3IgPSAyLjIsZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpKQpkZXYub2ZmKCkKYGBgCgojIyBBVkVSQUdFIEdFTkUgQ09VTlRTCmBgYHtyfQpJZGVudHMobmV3LnNraW4uY29tYmluZWQpIDwtICJzZXVyYXRfY2x1c3RlcnMiCgpjbHVzdGVycyA8LSB1bmlxdWUobmV3LnNraW4uY29tYmluZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykgJT4lIGFzLnZlY3RvcigpCgpmb3IoeCBpbiBjbHVzdGVycyl7CiAgYXZnX2V4cC5jbHVzdGVyIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKG5ldy5za2luLmNvbWJpbmVkLHNsb3QgPSAiY291bnRzIixhc3NheT0iU3BhdGlhbCIpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QocGFzdGUoIlNwYXRpYWwuIix4LHNlcCA9ICIiKSkgJT4lIGZpbHRlcih4PjApICU+JSB3cml0ZS5jc3YoZmlsZSA9IHBhc3RlKCJDTFVTVEVSXyIseCwiX0dFTkVfQ09VTlRTLmNzdiIsc2VwID0gIiIpKQp9CmBgYAoKYGBge3J9CmF2Z19leHAuYWxsX2NsdXN0ZXJzIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKG5ldy5za2luLmNvbWJpbmVkLHNsb3QgPSAiY291bnRzIixhc3NheT0iU3BhdGlhbCIpICU+JSBhcy5kYXRhLmZyYW1lKCkKd3JpdGUuY3N2KGF2Z19leHAuYWxsX2NsdXN0ZXJzLGZpbGU9IkFMTF9DTFVTVEVSU19HRU5FX0NPVU5UUy5jc3YiKQoKYXZnX2V4cC5jbHVzdGVyXzQgPC0gQXZlcmFnZUV4cHJlc3Npb24obmV3LnNraW4uY29tYmluZWQsc2xvdCA9ICJjb3VudHMiLGFzc2F5PSJTcGF0aWFsIikgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdCgiU3BhdGlhbC40Lkh5cG9kZXJtaXMiKSAlPiUgZmlsdGVyKFNwYXRpYWwuNC5IeXBvZGVybWlzPjApCndyaXRlLmNzdihhdmdfZXhwLmNsdXN0ZXJfNCxmaWxlPSJDTFVTVEVSXzRfR0VORV9DT1VOVFMuY3N2IikKYXZnX2V4cC5jbHVzdGVyXzIgPC0gQXZlcmFnZUV4cHJlc3Npb24obmV3LnNraW4uY29tYmluZWQsc2xvdCA9ICJjb3VudHMiLGFzc2F5PSJTcGF0aWFsIikgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdCgiU3BhdGlhbC4yLkRlcm1pcy5hZGlwb3NlIikgJT4lIGZpbHRlcihTcGF0aWFsLjIuRGVybWlzLmFkaXBvc2U+MCkKd3JpdGUuY3N2KGF2Z19leHAuY2x1c3Rlcl8yLGZpbGU9IkNMVVNURVJfMl9HRU5FX0NPVU5UUy5jc3YiKQpgYGAKCiMjIEhBTk5JRkEgREFUQSAtIE5FVyBVTUFQCmBgYHtyfQpoZWFsdGh5X3NraW4uc2NfZGF0YSA8LSBGaW5kTmVpZ2hib3JzKGhlYWx0aHlfc2tpbi5zY19kYXRhLCBkaW1zID0gMTo0MCkKaGVhbHRoeV9za2luLnNjX2RhdGEgPC0gRmluZENsdXN0ZXJzKGhlYWx0aHlfc2tpbi5zY19kYXRhLCB2ZXJib3NlID0gRkFMU0UscmVzb2x1dGlvbiA9IDEpCmhlYWx0aHlfc2tpbi5zY19kYXRhIDwtIFJ1blVNQVAoaGVhbHRoeV9za2luLnNjX2RhdGEsIGRpbXMgPSAxOjQwKQpgYGAKYGBge3J9CklkZW50cyhoZWFsdGh5X3NraW4uc2NfZGF0YSkgPC0gImZpbmFsX2NsdXN0ZXJpbmciCmhlYWx0aHlfc2tpbi5zY19kYXRhIDwtIHN1YnNldChoZWFsdGh5X3NraW4uc2NfZGF0YSxpZGVudHMgPSBjKCJuYW4iKSxpbnZlcnQ9VFJVRSkKYGBgCgpgYGB7cn0KcGRmKHdpZHRoID0gMTIsaGVpZ2h0PTgsZmlsZSA9ICJVTUFQX0hBTk5JRkFfREFUQV9IRUFMVEhZX1NBTVBMRVNfT05MWS5wZGYiKQpEaW1QbG90KGhlYWx0aHlfc2tpbi5zY19kYXRhLHB0LnNpemUgPSAzLjUscmFzdGVyPUZBTFNFKQpkZXYub2ZmKCkKYGBgCgojIFNJTkdMRSBDRUxMIERBVEEgLSBFTlJJQ0hNRU5UIFBMT1RTIChVU0lORyBPTkxZIE9ORSBIRUFMVEhZIFNBTVBMRSkKYGBge3J9CkhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbjwtIHN0X2ZpbHRlcl9ieV9nZW5lcyhzdC5kYXRhID0gSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuLHggPSAyMDApCkhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbiA8LSBTQ1RyYW5zZm9ybShIRUFMVEhZLkZlbWFsZTEuczIuY2xlYW4sIHZlcmJvc2UgPSBGQUxTRSxhc3NheT0iU3BhdGlhbCIpCkhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbiA8LSBSdW5QQ0EoSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuKQpgYGAKCmBgYHtyfQojdHJhdmlzX05NX3NraW5fc2NSTkEgPC0gcmVhZFJEUyhmaWxlPSIuLi8uLi9UUkFWSVNfc2NSTkFfREFUQS90cmF2aXNfTk1fc2tpbl9zY1JOQS5SRFMiKQojIFJVTiBUSElTIE9OIEJJRyBQVVJQTEUgCnNraW5fcmVmZXJlbmNlLjMgPC0gU0NUcmFuc2Zvcm0odHJhdmlzX05NX3NraW5fc2NSTkEsIG5jZWxscyA9IDMwMDAsIHZlcmJvc2UgPSBGQUxTRSkgJT4lIFJ1blBDQSh2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgIFJ1blVNQVAoZGltcyA9IDE6NDApCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBza2luX3JlZmVyZW5jZS4zLCBxdWVyeSA9IEhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbiwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIikKcHJlZGljdGlvbnMuYXNzYXkgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBza2luX3JlZmVyZW5jZS4zJFNwZWNpZmljX0NlbGxUeXBlLCBwcmVkaWN0aW9uLmFzc2F5ID0gVFJVRSwgCiAgICB3ZWlnaHQucmVkdWN0aW9uID0gSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuW1sicGNhIl1dLGRpbXMgPSAxOjQwKQpIRUFMVEhZLkZlbWFsZTEuczIuY2xlYW5bWyJwcmVkaWN0aW9uc190cmF2aXNfZGF0YSJdXSA8LSBwcmVkaWN0aW9ucy5hc3NheQoKYGBgCmBgYHtyfQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKU3BhdGlhbENvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IHJldih4ID0gYnJld2VyLnBhbChuID0gMTEsIG5hbWUgPSAiU3BlY3RyYWwiKSkpCmNvbHMgPC0gU3BhdGlhbENvbG9ycyhuID0gMTAwKQpgYGAKCmBgYHtyfQpTcGF0aWFsRmVhdHVyZVBsb3QoSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuLGZlYXR1cmVzID0gYygiTWVsYW5vY3l0ZSIpLCBwdC5zaXplLmZhY3RvciA9IDIuNSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jb2xzLGxpbWl0cyA9IGMoMCwxLjAwMDAwMSkpCgpTcGF0aWFsRmVhdHVyZVBsb3QoSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuLGZlYXR1cmVzID0gYygiVlNNQy0xIiksIHB0LnNpemUuZmFjdG9yID0gMi41KSsgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWNvbHMsbGltaXRzID0gYygwLDEuMDAwMDAxKSkKClNwYXRpYWxGZWF0dXJlUGxvdChIRUFMVEhZLkZlbWFsZTEuczIuY2xlYW4sZmVhdHVyZXMgPSBjKCJIYWlyRm9sbGljbGUiKSwgcHQuc2l6ZS5mYWN0b3IgPSAyLjUpKyBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Y29scyxsaW1pdHMgPSBjKDAsMS4wMDAwMDEpKQoKU3BhdGlhbEZlYXR1cmVQbG90KEhFQUxUSFkuRmVtYWxlMS5zMi5jbGVhbixmZWF0dXJlcyA9IGMoIktlcmF0aW5vY3l0ZS01IiksIHB0LnNpemUuZmFjdG9yID0gMi41KSsgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWNvbHMsbGltaXRzID0gYygwLDEuMDAwMDAxKSkKClNwYXRpYWxGZWF0dXJlUGxvdChIRUFMVEhZLkZlbWFsZTEuczIuY2xlYW4sZmVhdHVyZXMgPSBjKCJTZWJvY3l0ZSIpLCBwdC5zaXplLmZhY3RvciA9IDIuNSkrIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jb2xzLGxpbWl0cyA9IGMoMCwxLjAwMDAwMSkpCgpTcGF0aWFsRmVhdHVyZVBsb3QoSEVBTFRIWS5GZW1hbGUxLnMyLmNsZWFuLGZlYXR1cmVzID0gYygiRmlicm9ibGFzdC0xIiksIHB0LnNpemUuZmFjdG9yID0gMi41KSsgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWNvbHMsbGltaXRzID0gYygwLDEuMDAwMDAxKSkKYGBgCg==